@elia-ori/editor 0.1.0
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/dist/index.cjs +4928 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +128 -0
- package/dist/index.d.ts +128 -0
- package/dist/index.js +4893 -0
- package/dist/index.js.map +1 -0
- package/dist/styles/editor.css +277 -0
- package/dist/styles/editor.css.map +1 -0
- package/dist/styles/editor.d.cts +2 -0
- package/dist/styles/editor.d.ts +2 -0
- package/package.json +92 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,4928 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var index_exports = {};
|
|
32
|
+
__export(index_exports, {
|
|
33
|
+
Button: () => Button,
|
|
34
|
+
Callout: () => Callout,
|
|
35
|
+
CalloutDropdown: () => CalloutDropdown,
|
|
36
|
+
ColorPicker: () => ColorPicker,
|
|
37
|
+
DropdownMenu: () => DropdownMenu,
|
|
38
|
+
DropdownMenuContent: () => DropdownMenuContent,
|
|
39
|
+
DropdownMenuItem: () => DropdownMenuItem,
|
|
40
|
+
DropdownMenuSeparator: () => DropdownMenuSeparator,
|
|
41
|
+
DropdownMenuTrigger: () => DropdownMenuTrigger,
|
|
42
|
+
EliaEditor: () => EliaEditor,
|
|
43
|
+
HeadingDropdown: () => HeadingDropdown,
|
|
44
|
+
ListDropdown: () => ListDropdown,
|
|
45
|
+
TableDropdown: () => TableDropdown,
|
|
46
|
+
Toggle: () => Toggle,
|
|
47
|
+
Toolbar: () => Toolbar,
|
|
48
|
+
ToolbarButton: () => ToolbarButton,
|
|
49
|
+
ToolbarDivider: () => ToolbarDivider,
|
|
50
|
+
cn: () => cn
|
|
51
|
+
});
|
|
52
|
+
module.exports = __toCommonJS(index_exports);
|
|
53
|
+
|
|
54
|
+
// src/EliaEditor.tsx
|
|
55
|
+
var import_react3 = require("react");
|
|
56
|
+
var import_react4 = require("@tiptap/react");
|
|
57
|
+
var import_starter_kit = __toESM(require("@tiptap/starter-kit"), 1);
|
|
58
|
+
var import_extension_placeholder = __toESM(require("@tiptap/extension-placeholder"), 1);
|
|
59
|
+
var import_extension_underline = __toESM(require("@tiptap/extension-underline"), 1);
|
|
60
|
+
var import_extension_text_align = __toESM(require("@tiptap/extension-text-align"), 1);
|
|
61
|
+
var import_extension_link = __toESM(require("@tiptap/extension-link"), 1);
|
|
62
|
+
var import_extension_text_style = require("@tiptap/extension-text-style");
|
|
63
|
+
var import_extension_color = require("@tiptap/extension-color");
|
|
64
|
+
var import_extension_highlight = require("@tiptap/extension-highlight");
|
|
65
|
+
var import_extension_subscript = __toESM(require("@tiptap/extension-subscript"), 1);
|
|
66
|
+
var import_extension_superscript = __toESM(require("@tiptap/extension-superscript"), 1);
|
|
67
|
+
var import_extension_task_list = __toESM(require("@tiptap/extension-task-list"), 1);
|
|
68
|
+
var import_extension_task_item = __toESM(require("@tiptap/extension-task-item"), 1);
|
|
69
|
+
var import_extension_table = require("@tiptap/extension-table");
|
|
70
|
+
var import_extension_table_row = require("@tiptap/extension-table-row");
|
|
71
|
+
var import_extension_table_header = require("@tiptap/extension-table-header");
|
|
72
|
+
var import_extension_table_cell = require("@tiptap/extension-table-cell");
|
|
73
|
+
var import_tiptap_extension_resize_image = __toESM(require("tiptap-extension-resize-image"), 1);
|
|
74
|
+
|
|
75
|
+
// node_modules/@tiptap/core/dist/index.js
|
|
76
|
+
var import_transform = require("@tiptap/pm/transform");
|
|
77
|
+
var import_commands = require("@tiptap/pm/commands");
|
|
78
|
+
var import_state = require("@tiptap/pm/state");
|
|
79
|
+
var import_commands2 = require("@tiptap/pm/commands");
|
|
80
|
+
var import_commands3 = require("@tiptap/pm/commands");
|
|
81
|
+
var import_state2 = require("@tiptap/pm/state");
|
|
82
|
+
var import_state3 = require("@tiptap/pm/state");
|
|
83
|
+
var import_state4 = require("@tiptap/pm/state");
|
|
84
|
+
var import_model = require("@tiptap/pm/model");
|
|
85
|
+
var import_model2 = require("@tiptap/pm/model");
|
|
86
|
+
var import_state5 = require("@tiptap/pm/state");
|
|
87
|
+
var import_transform2 = require("@tiptap/pm/transform");
|
|
88
|
+
var import_commands4 = require("@tiptap/pm/commands");
|
|
89
|
+
var import_transform3 = require("@tiptap/pm/transform");
|
|
90
|
+
var import_transform4 = require("@tiptap/pm/transform");
|
|
91
|
+
var import_commands5 = require("@tiptap/pm/commands");
|
|
92
|
+
var import_commands6 = require("@tiptap/pm/commands");
|
|
93
|
+
var import_commands7 = require("@tiptap/pm/commands");
|
|
94
|
+
var import_commands8 = require("@tiptap/pm/commands");
|
|
95
|
+
var import_schema_list = require("@tiptap/pm/schema-list");
|
|
96
|
+
var import_commands9 = require("@tiptap/pm/commands");
|
|
97
|
+
var import_state6 = require("@tiptap/pm/state");
|
|
98
|
+
var import_commands10 = require("@tiptap/pm/commands");
|
|
99
|
+
var import_commands11 = require("@tiptap/pm/commands");
|
|
100
|
+
var import_commands12 = require("@tiptap/pm/commands");
|
|
101
|
+
var import_commands13 = require("@tiptap/pm/commands");
|
|
102
|
+
var import_commands14 = require("@tiptap/pm/commands");
|
|
103
|
+
var import_transform5 = require("@tiptap/pm/transform");
|
|
104
|
+
var import_model3 = require("@tiptap/pm/model");
|
|
105
|
+
var import_model4 = require("@tiptap/pm/model");
|
|
106
|
+
var import_model5 = require("@tiptap/pm/model");
|
|
107
|
+
var import_model6 = require("@tiptap/pm/model");
|
|
108
|
+
var import_model7 = require("@tiptap/pm/model");
|
|
109
|
+
var import_state7 = require("@tiptap/pm/state");
|
|
110
|
+
var import_commands15 = require("@tiptap/pm/commands");
|
|
111
|
+
var import_state8 = require("@tiptap/pm/state");
|
|
112
|
+
var import_state9 = require("@tiptap/pm/state");
|
|
113
|
+
var import_schema_list2 = require("@tiptap/pm/schema-list");
|
|
114
|
+
var import_state10 = require("@tiptap/pm/state");
|
|
115
|
+
var import_transform6 = require("@tiptap/pm/transform");
|
|
116
|
+
var import_model8 = require("@tiptap/pm/model");
|
|
117
|
+
var import_state11 = require("@tiptap/pm/state");
|
|
118
|
+
var import_transform7 = require("@tiptap/pm/transform");
|
|
119
|
+
var import_transform8 = require("@tiptap/pm/transform");
|
|
120
|
+
var import_commands16 = require("@tiptap/pm/commands");
|
|
121
|
+
var import_schema_list3 = require("@tiptap/pm/schema-list");
|
|
122
|
+
var import_state12 = require("@tiptap/pm/state");
|
|
123
|
+
var import_view = require("@tiptap/pm/view");
|
|
124
|
+
var import_keymap = require("@tiptap/pm/keymap");
|
|
125
|
+
var import_model9 = require("@tiptap/pm/model");
|
|
126
|
+
var import_state13 = require("@tiptap/pm/state");
|
|
127
|
+
var import_model10 = require("@tiptap/pm/model");
|
|
128
|
+
var import_state14 = require("@tiptap/pm/state");
|
|
129
|
+
var import_state15 = require("@tiptap/pm/state");
|
|
130
|
+
var import_transform9 = require("@tiptap/pm/transform");
|
|
131
|
+
var import_state16 = require("@tiptap/pm/state");
|
|
132
|
+
var import_state17 = require("@tiptap/pm/state");
|
|
133
|
+
var import_state18 = require("@tiptap/pm/state");
|
|
134
|
+
var import_state19 = require("@tiptap/pm/state");
|
|
135
|
+
var import_state20 = require("@tiptap/pm/state");
|
|
136
|
+
var import_state21 = require("@tiptap/pm/state");
|
|
137
|
+
var import_state22 = require("@tiptap/pm/state");
|
|
138
|
+
var import_transform10 = require("@tiptap/pm/transform");
|
|
139
|
+
var import_state23 = require("@tiptap/pm/state");
|
|
140
|
+
var import_state24 = require("@tiptap/pm/state");
|
|
141
|
+
var __defProp2 = Object.defineProperty;
|
|
142
|
+
var __export2 = (target, all) => {
|
|
143
|
+
for (var name in all)
|
|
144
|
+
__defProp2(target, name, { get: all[name], enumerable: true });
|
|
145
|
+
};
|
|
146
|
+
function createChainableState(config) {
|
|
147
|
+
const { state, transaction } = config;
|
|
148
|
+
let { selection } = transaction;
|
|
149
|
+
let { doc } = transaction;
|
|
150
|
+
let { storedMarks } = transaction;
|
|
151
|
+
return {
|
|
152
|
+
...state,
|
|
153
|
+
apply: state.apply.bind(state),
|
|
154
|
+
applyTransaction: state.applyTransaction.bind(state),
|
|
155
|
+
plugins: state.plugins,
|
|
156
|
+
schema: state.schema,
|
|
157
|
+
reconfigure: state.reconfigure.bind(state),
|
|
158
|
+
toJSON: state.toJSON.bind(state),
|
|
159
|
+
get storedMarks() {
|
|
160
|
+
return storedMarks;
|
|
161
|
+
},
|
|
162
|
+
get selection() {
|
|
163
|
+
return selection;
|
|
164
|
+
},
|
|
165
|
+
get doc() {
|
|
166
|
+
return doc;
|
|
167
|
+
},
|
|
168
|
+
get tr() {
|
|
169
|
+
selection = transaction.selection;
|
|
170
|
+
doc = transaction.doc;
|
|
171
|
+
storedMarks = transaction.storedMarks;
|
|
172
|
+
return transaction;
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
var CommandManager = class {
|
|
177
|
+
constructor(props) {
|
|
178
|
+
this.editor = props.editor;
|
|
179
|
+
this.rawCommands = this.editor.extensionManager.commands;
|
|
180
|
+
this.customState = props.state;
|
|
181
|
+
}
|
|
182
|
+
get hasCustomState() {
|
|
183
|
+
return !!this.customState;
|
|
184
|
+
}
|
|
185
|
+
get state() {
|
|
186
|
+
return this.customState || this.editor.state;
|
|
187
|
+
}
|
|
188
|
+
get commands() {
|
|
189
|
+
const { rawCommands, editor, state } = this;
|
|
190
|
+
const { view } = editor;
|
|
191
|
+
const { tr } = state;
|
|
192
|
+
const props = this.buildProps(tr);
|
|
193
|
+
return Object.fromEntries(
|
|
194
|
+
Object.entries(rawCommands).map(([name, command2]) => {
|
|
195
|
+
const method = (...args) => {
|
|
196
|
+
const callback = command2(...args)(props);
|
|
197
|
+
if (!tr.getMeta("preventDispatch") && !this.hasCustomState) {
|
|
198
|
+
view.dispatch(tr);
|
|
199
|
+
}
|
|
200
|
+
return callback;
|
|
201
|
+
};
|
|
202
|
+
return [name, method];
|
|
203
|
+
})
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
get chain() {
|
|
207
|
+
return () => this.createChain();
|
|
208
|
+
}
|
|
209
|
+
get can() {
|
|
210
|
+
return () => this.createCan();
|
|
211
|
+
}
|
|
212
|
+
createChain(startTr, shouldDispatch = true) {
|
|
213
|
+
const { rawCommands, editor, state } = this;
|
|
214
|
+
const { view } = editor;
|
|
215
|
+
const callbacks = [];
|
|
216
|
+
const hasStartTransaction = !!startTr;
|
|
217
|
+
const tr = startTr || state.tr;
|
|
218
|
+
const run3 = () => {
|
|
219
|
+
if (!hasStartTransaction && shouldDispatch && !tr.getMeta("preventDispatch") && !this.hasCustomState) {
|
|
220
|
+
view.dispatch(tr);
|
|
221
|
+
}
|
|
222
|
+
return callbacks.every((callback) => callback === true);
|
|
223
|
+
};
|
|
224
|
+
const chain = {
|
|
225
|
+
...Object.fromEntries(
|
|
226
|
+
Object.entries(rawCommands).map(([name, command2]) => {
|
|
227
|
+
const chainedCommand = (...args) => {
|
|
228
|
+
const props = this.buildProps(tr, shouldDispatch);
|
|
229
|
+
const callback = command2(...args)(props);
|
|
230
|
+
callbacks.push(callback);
|
|
231
|
+
return chain;
|
|
232
|
+
};
|
|
233
|
+
return [name, chainedCommand];
|
|
234
|
+
})
|
|
235
|
+
),
|
|
236
|
+
run: run3
|
|
237
|
+
};
|
|
238
|
+
return chain;
|
|
239
|
+
}
|
|
240
|
+
createCan(startTr) {
|
|
241
|
+
const { rawCommands, state } = this;
|
|
242
|
+
const dispatch = false;
|
|
243
|
+
const tr = startTr || state.tr;
|
|
244
|
+
const props = this.buildProps(tr, dispatch);
|
|
245
|
+
const formattedCommands = Object.fromEntries(
|
|
246
|
+
Object.entries(rawCommands).map(([name, command2]) => {
|
|
247
|
+
return [name, (...args) => command2(...args)({ ...props, dispatch: void 0 })];
|
|
248
|
+
})
|
|
249
|
+
);
|
|
250
|
+
return {
|
|
251
|
+
...formattedCommands,
|
|
252
|
+
chain: () => this.createChain(tr, dispatch)
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
buildProps(tr, shouldDispatch = true) {
|
|
256
|
+
const { rawCommands, editor, state } = this;
|
|
257
|
+
const { view } = editor;
|
|
258
|
+
const props = {
|
|
259
|
+
tr,
|
|
260
|
+
editor,
|
|
261
|
+
view,
|
|
262
|
+
state: createChainableState({
|
|
263
|
+
state,
|
|
264
|
+
transaction: tr
|
|
265
|
+
}),
|
|
266
|
+
dispatch: shouldDispatch ? () => void 0 : void 0,
|
|
267
|
+
chain: () => this.createChain(tr, shouldDispatch),
|
|
268
|
+
can: () => this.createCan(tr),
|
|
269
|
+
get commands() {
|
|
270
|
+
return Object.fromEntries(
|
|
271
|
+
Object.entries(rawCommands).map(([name, command2]) => {
|
|
272
|
+
return [name, (...args) => command2(...args)(props)];
|
|
273
|
+
})
|
|
274
|
+
);
|
|
275
|
+
}
|
|
276
|
+
};
|
|
277
|
+
return props;
|
|
278
|
+
}
|
|
279
|
+
};
|
|
280
|
+
var commands_exports = {};
|
|
281
|
+
__export2(commands_exports, {
|
|
282
|
+
blur: () => blur,
|
|
283
|
+
clearContent: () => clearContent,
|
|
284
|
+
clearNodes: () => clearNodes,
|
|
285
|
+
command: () => command,
|
|
286
|
+
createParagraphNear: () => createParagraphNear,
|
|
287
|
+
cut: () => cut,
|
|
288
|
+
deleteCurrentNode: () => deleteCurrentNode,
|
|
289
|
+
deleteNode: () => deleteNode,
|
|
290
|
+
deleteRange: () => deleteRange,
|
|
291
|
+
deleteSelection: () => deleteSelection,
|
|
292
|
+
enter: () => enter,
|
|
293
|
+
exitCode: () => exitCode,
|
|
294
|
+
extendMarkRange: () => extendMarkRange,
|
|
295
|
+
first: () => first,
|
|
296
|
+
focus: () => focus,
|
|
297
|
+
forEach: () => forEach,
|
|
298
|
+
insertContent: () => insertContent,
|
|
299
|
+
insertContentAt: () => insertContentAt,
|
|
300
|
+
joinBackward: () => joinBackward,
|
|
301
|
+
joinDown: () => joinDown,
|
|
302
|
+
joinForward: () => joinForward,
|
|
303
|
+
joinItemBackward: () => joinItemBackward,
|
|
304
|
+
joinItemForward: () => joinItemForward,
|
|
305
|
+
joinTextblockBackward: () => joinTextblockBackward,
|
|
306
|
+
joinTextblockForward: () => joinTextblockForward,
|
|
307
|
+
joinUp: () => joinUp,
|
|
308
|
+
keyboardShortcut: () => keyboardShortcut,
|
|
309
|
+
lift: () => lift,
|
|
310
|
+
liftEmptyBlock: () => liftEmptyBlock,
|
|
311
|
+
liftListItem: () => liftListItem,
|
|
312
|
+
newlineInCode: () => newlineInCode,
|
|
313
|
+
resetAttributes: () => resetAttributes,
|
|
314
|
+
scrollIntoView: () => scrollIntoView,
|
|
315
|
+
selectAll: () => selectAll,
|
|
316
|
+
selectNodeBackward: () => selectNodeBackward,
|
|
317
|
+
selectNodeForward: () => selectNodeForward,
|
|
318
|
+
selectParentNode: () => selectParentNode,
|
|
319
|
+
selectTextblockEnd: () => selectTextblockEnd,
|
|
320
|
+
selectTextblockStart: () => selectTextblockStart,
|
|
321
|
+
setContent: () => setContent,
|
|
322
|
+
setMark: () => setMark,
|
|
323
|
+
setMeta: () => setMeta,
|
|
324
|
+
setNode: () => setNode,
|
|
325
|
+
setNodeSelection: () => setNodeSelection,
|
|
326
|
+
setTextDirection: () => setTextDirection,
|
|
327
|
+
setTextSelection: () => setTextSelection,
|
|
328
|
+
sinkListItem: () => sinkListItem,
|
|
329
|
+
splitBlock: () => splitBlock,
|
|
330
|
+
splitListItem: () => splitListItem,
|
|
331
|
+
toggleList: () => toggleList,
|
|
332
|
+
toggleMark: () => toggleMark,
|
|
333
|
+
toggleNode: () => toggleNode,
|
|
334
|
+
toggleWrap: () => toggleWrap,
|
|
335
|
+
undoInputRule: () => undoInputRule,
|
|
336
|
+
unsetAllMarks: () => unsetAllMarks,
|
|
337
|
+
unsetMark: () => unsetMark,
|
|
338
|
+
unsetTextDirection: () => unsetTextDirection,
|
|
339
|
+
updateAttributes: () => updateAttributes,
|
|
340
|
+
wrapIn: () => wrapIn,
|
|
341
|
+
wrapInList: () => wrapInList
|
|
342
|
+
});
|
|
343
|
+
var blur = () => ({ editor, view }) => {
|
|
344
|
+
requestAnimationFrame(() => {
|
|
345
|
+
var _a;
|
|
346
|
+
if (!editor.isDestroyed) {
|
|
347
|
+
;
|
|
348
|
+
view.dom.blur();
|
|
349
|
+
(_a = window == null ? void 0 : window.getSelection()) == null ? void 0 : _a.removeAllRanges();
|
|
350
|
+
}
|
|
351
|
+
});
|
|
352
|
+
return true;
|
|
353
|
+
};
|
|
354
|
+
var clearContent = (emitUpdate = true) => ({ commands }) => {
|
|
355
|
+
return commands.setContent("", { emitUpdate });
|
|
356
|
+
};
|
|
357
|
+
var clearNodes = () => ({ state, tr, dispatch }) => {
|
|
358
|
+
const { selection } = tr;
|
|
359
|
+
const { ranges } = selection;
|
|
360
|
+
if (!dispatch) {
|
|
361
|
+
return true;
|
|
362
|
+
}
|
|
363
|
+
ranges.forEach(({ $from, $to }) => {
|
|
364
|
+
state.doc.nodesBetween($from.pos, $to.pos, (node, pos) => {
|
|
365
|
+
if (node.type.isText) {
|
|
366
|
+
return;
|
|
367
|
+
}
|
|
368
|
+
const { doc, mapping } = tr;
|
|
369
|
+
const $mappedFrom = doc.resolve(mapping.map(pos));
|
|
370
|
+
const $mappedTo = doc.resolve(mapping.map(pos + node.nodeSize));
|
|
371
|
+
const nodeRange = $mappedFrom.blockRange($mappedTo);
|
|
372
|
+
if (!nodeRange) {
|
|
373
|
+
return;
|
|
374
|
+
}
|
|
375
|
+
const targetLiftDepth = (0, import_transform.liftTarget)(nodeRange);
|
|
376
|
+
if (node.type.isTextblock) {
|
|
377
|
+
const { defaultType } = $mappedFrom.parent.contentMatchAt($mappedFrom.index());
|
|
378
|
+
tr.setNodeMarkup(nodeRange.start, defaultType);
|
|
379
|
+
}
|
|
380
|
+
if (targetLiftDepth || targetLiftDepth === 0) {
|
|
381
|
+
tr.lift(nodeRange, targetLiftDepth);
|
|
382
|
+
}
|
|
383
|
+
});
|
|
384
|
+
});
|
|
385
|
+
return true;
|
|
386
|
+
};
|
|
387
|
+
var command = (fn) => (props) => {
|
|
388
|
+
return fn(props);
|
|
389
|
+
};
|
|
390
|
+
var createParagraphNear = () => ({ state, dispatch }) => {
|
|
391
|
+
return (0, import_commands.createParagraphNear)(state, dispatch);
|
|
392
|
+
};
|
|
393
|
+
var cut = (originRange, targetPos) => ({ editor, tr }) => {
|
|
394
|
+
const { state } = editor;
|
|
395
|
+
const contentSlice = state.doc.slice(originRange.from, originRange.to);
|
|
396
|
+
tr.deleteRange(originRange.from, originRange.to);
|
|
397
|
+
const newPos = tr.mapping.map(targetPos);
|
|
398
|
+
tr.insert(newPos, contentSlice.content);
|
|
399
|
+
tr.setSelection(new import_state.TextSelection(tr.doc.resolve(Math.max(newPos - 1, 0))));
|
|
400
|
+
return true;
|
|
401
|
+
};
|
|
402
|
+
var deleteCurrentNode = () => ({ tr, dispatch }) => {
|
|
403
|
+
const { selection } = tr;
|
|
404
|
+
const currentNode = selection.$anchor.node();
|
|
405
|
+
if (currentNode.content.size > 0) {
|
|
406
|
+
return false;
|
|
407
|
+
}
|
|
408
|
+
const $pos = tr.selection.$anchor;
|
|
409
|
+
for (let depth = $pos.depth; depth > 0; depth -= 1) {
|
|
410
|
+
const node = $pos.node(depth);
|
|
411
|
+
if (node.type === currentNode.type) {
|
|
412
|
+
if (dispatch) {
|
|
413
|
+
const from = $pos.before(depth);
|
|
414
|
+
const to = $pos.after(depth);
|
|
415
|
+
tr.delete(from, to).scrollIntoView();
|
|
416
|
+
}
|
|
417
|
+
return true;
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
return false;
|
|
421
|
+
};
|
|
422
|
+
function getNodeType(nameOrType, schema) {
|
|
423
|
+
if (typeof nameOrType === "string") {
|
|
424
|
+
if (!schema.nodes[nameOrType]) {
|
|
425
|
+
throw Error(`There is no node type named '${nameOrType}'. Maybe you forgot to add the extension?`);
|
|
426
|
+
}
|
|
427
|
+
return schema.nodes[nameOrType];
|
|
428
|
+
}
|
|
429
|
+
return nameOrType;
|
|
430
|
+
}
|
|
431
|
+
var deleteNode = (typeOrName) => ({ tr, state, dispatch }) => {
|
|
432
|
+
const type = getNodeType(typeOrName, state.schema);
|
|
433
|
+
const $pos = tr.selection.$anchor;
|
|
434
|
+
for (let depth = $pos.depth; depth > 0; depth -= 1) {
|
|
435
|
+
const node = $pos.node(depth);
|
|
436
|
+
if (node.type === type) {
|
|
437
|
+
if (dispatch) {
|
|
438
|
+
const from = $pos.before(depth);
|
|
439
|
+
const to = $pos.after(depth);
|
|
440
|
+
tr.delete(from, to).scrollIntoView();
|
|
441
|
+
}
|
|
442
|
+
return true;
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
return false;
|
|
446
|
+
};
|
|
447
|
+
var deleteRange = (range) => ({ tr, dispatch }) => {
|
|
448
|
+
const { from, to } = range;
|
|
449
|
+
if (dispatch) {
|
|
450
|
+
tr.delete(from, to);
|
|
451
|
+
}
|
|
452
|
+
return true;
|
|
453
|
+
};
|
|
454
|
+
var deleteSelection = () => ({ state, dispatch }) => {
|
|
455
|
+
return (0, import_commands2.deleteSelection)(state, dispatch);
|
|
456
|
+
};
|
|
457
|
+
var enter = () => ({ commands }) => {
|
|
458
|
+
return commands.keyboardShortcut("Enter");
|
|
459
|
+
};
|
|
460
|
+
var exitCode = () => ({ state, dispatch }) => {
|
|
461
|
+
return (0, import_commands3.exitCode)(state, dispatch);
|
|
462
|
+
};
|
|
463
|
+
function isRegExp(value) {
|
|
464
|
+
return Object.prototype.toString.call(value) === "[object RegExp]";
|
|
465
|
+
}
|
|
466
|
+
function objectIncludes(object1, object2, options = { strict: true }) {
|
|
467
|
+
const keys = Object.keys(object2);
|
|
468
|
+
if (!keys.length) {
|
|
469
|
+
return true;
|
|
470
|
+
}
|
|
471
|
+
return keys.every((key) => {
|
|
472
|
+
if (options.strict) {
|
|
473
|
+
return object2[key] === object1[key];
|
|
474
|
+
}
|
|
475
|
+
if (isRegExp(object2[key])) {
|
|
476
|
+
return object2[key].test(object1[key]);
|
|
477
|
+
}
|
|
478
|
+
return object2[key] === object1[key];
|
|
479
|
+
});
|
|
480
|
+
}
|
|
481
|
+
function findMarkInSet(marks, type, attributes = {}) {
|
|
482
|
+
return marks.find((item) => {
|
|
483
|
+
return item.type === type && objectIncludes(
|
|
484
|
+
// Only check equality for the attributes that are provided
|
|
485
|
+
Object.fromEntries(Object.keys(attributes).map((k) => [k, item.attrs[k]])),
|
|
486
|
+
attributes
|
|
487
|
+
);
|
|
488
|
+
});
|
|
489
|
+
}
|
|
490
|
+
function isMarkInSet(marks, type, attributes = {}) {
|
|
491
|
+
return !!findMarkInSet(marks, type, attributes);
|
|
492
|
+
}
|
|
493
|
+
function getMarkRange($pos, type, attributes) {
|
|
494
|
+
var _a;
|
|
495
|
+
if (!$pos || !type) {
|
|
496
|
+
return;
|
|
497
|
+
}
|
|
498
|
+
let start = $pos.parent.childAfter($pos.parentOffset);
|
|
499
|
+
if (!start.node || !start.node.marks.some((mark2) => mark2.type === type)) {
|
|
500
|
+
start = $pos.parent.childBefore($pos.parentOffset);
|
|
501
|
+
}
|
|
502
|
+
if (!start.node || !start.node.marks.some((mark2) => mark2.type === type)) {
|
|
503
|
+
return;
|
|
504
|
+
}
|
|
505
|
+
attributes = attributes || ((_a = start.node.marks[0]) == null ? void 0 : _a.attrs);
|
|
506
|
+
const mark = findMarkInSet([...start.node.marks], type, attributes);
|
|
507
|
+
if (!mark) {
|
|
508
|
+
return;
|
|
509
|
+
}
|
|
510
|
+
let startIndex = start.index;
|
|
511
|
+
let startPos = $pos.start() + start.offset;
|
|
512
|
+
let endIndex = startIndex + 1;
|
|
513
|
+
let endPos = startPos + start.node.nodeSize;
|
|
514
|
+
while (startIndex > 0 && isMarkInSet([...$pos.parent.child(startIndex - 1).marks], type, attributes)) {
|
|
515
|
+
startIndex -= 1;
|
|
516
|
+
startPos -= $pos.parent.child(startIndex).nodeSize;
|
|
517
|
+
}
|
|
518
|
+
while (endIndex < $pos.parent.childCount && isMarkInSet([...$pos.parent.child(endIndex).marks], type, attributes)) {
|
|
519
|
+
endPos += $pos.parent.child(endIndex).nodeSize;
|
|
520
|
+
endIndex += 1;
|
|
521
|
+
}
|
|
522
|
+
return {
|
|
523
|
+
from: startPos,
|
|
524
|
+
to: endPos
|
|
525
|
+
};
|
|
526
|
+
}
|
|
527
|
+
function getMarkType(nameOrType, schema) {
|
|
528
|
+
if (typeof nameOrType === "string") {
|
|
529
|
+
if (!schema.marks[nameOrType]) {
|
|
530
|
+
throw Error(`There is no mark type named '${nameOrType}'. Maybe you forgot to add the extension?`);
|
|
531
|
+
}
|
|
532
|
+
return schema.marks[nameOrType];
|
|
533
|
+
}
|
|
534
|
+
return nameOrType;
|
|
535
|
+
}
|
|
536
|
+
var extendMarkRange = (typeOrName, attributes = {}) => ({ tr, state, dispatch }) => {
|
|
537
|
+
const type = getMarkType(typeOrName, state.schema);
|
|
538
|
+
const { doc, selection } = tr;
|
|
539
|
+
const { $from, from, to } = selection;
|
|
540
|
+
if (dispatch) {
|
|
541
|
+
const range = getMarkRange($from, type, attributes);
|
|
542
|
+
if (range && range.from <= from && range.to >= to) {
|
|
543
|
+
const newSelection = import_state2.TextSelection.create(doc, range.from, range.to);
|
|
544
|
+
tr.setSelection(newSelection);
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
return true;
|
|
548
|
+
};
|
|
549
|
+
var first = (commands) => (props) => {
|
|
550
|
+
const items = typeof commands === "function" ? commands(props) : commands;
|
|
551
|
+
for (let i = 0; i < items.length; i += 1) {
|
|
552
|
+
if (items[i](props)) {
|
|
553
|
+
return true;
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
return false;
|
|
557
|
+
};
|
|
558
|
+
function isTextSelection(value) {
|
|
559
|
+
return value instanceof import_state3.TextSelection;
|
|
560
|
+
}
|
|
561
|
+
function minMax(value = 0, min = 0, max = 0) {
|
|
562
|
+
return Math.min(Math.max(value, min), max);
|
|
563
|
+
}
|
|
564
|
+
function resolveFocusPosition(doc, position = null) {
|
|
565
|
+
if (!position) {
|
|
566
|
+
return null;
|
|
567
|
+
}
|
|
568
|
+
const selectionAtStart = import_state4.Selection.atStart(doc);
|
|
569
|
+
const selectionAtEnd = import_state4.Selection.atEnd(doc);
|
|
570
|
+
if (position === "start" || position === true) {
|
|
571
|
+
return selectionAtStart;
|
|
572
|
+
}
|
|
573
|
+
if (position === "end") {
|
|
574
|
+
return selectionAtEnd;
|
|
575
|
+
}
|
|
576
|
+
const minPos = selectionAtStart.from;
|
|
577
|
+
const maxPos = selectionAtEnd.to;
|
|
578
|
+
if (position === "all") {
|
|
579
|
+
return import_state4.TextSelection.create(doc, minMax(0, minPos, maxPos), minMax(doc.content.size, minPos, maxPos));
|
|
580
|
+
}
|
|
581
|
+
return import_state4.TextSelection.create(doc, minMax(position, minPos, maxPos), minMax(position, minPos, maxPos));
|
|
582
|
+
}
|
|
583
|
+
function isAndroid() {
|
|
584
|
+
return navigator.platform === "Android" || /android/i.test(navigator.userAgent);
|
|
585
|
+
}
|
|
586
|
+
function isiOS() {
|
|
587
|
+
return ["iPad Simulator", "iPhone Simulator", "iPod Simulator", "iPad", "iPhone", "iPod"].includes(navigator.platform) || // iPad on iOS 13 detection
|
|
588
|
+
navigator.userAgent.includes("Mac") && "ontouchend" in document;
|
|
589
|
+
}
|
|
590
|
+
function isSafari() {
|
|
591
|
+
return typeof navigator !== "undefined" ? /^((?!chrome|android).)*safari/i.test(navigator.userAgent) : false;
|
|
592
|
+
}
|
|
593
|
+
var focus = (position = null, options = {}) => ({ editor, view, tr, dispatch }) => {
|
|
594
|
+
options = {
|
|
595
|
+
scrollIntoView: true,
|
|
596
|
+
...options
|
|
597
|
+
};
|
|
598
|
+
const delayedFocus = () => {
|
|
599
|
+
if (isiOS() || isAndroid()) {
|
|
600
|
+
;
|
|
601
|
+
view.dom.focus();
|
|
602
|
+
}
|
|
603
|
+
if (isSafari() && !isiOS() && !isAndroid()) {
|
|
604
|
+
;
|
|
605
|
+
view.dom.focus({ preventScroll: true });
|
|
606
|
+
}
|
|
607
|
+
requestAnimationFrame(() => {
|
|
608
|
+
if (!editor.isDestroyed) {
|
|
609
|
+
view.focus();
|
|
610
|
+
if (options == null ? void 0 : options.scrollIntoView) {
|
|
611
|
+
editor.commands.scrollIntoView();
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
});
|
|
615
|
+
};
|
|
616
|
+
if (view.hasFocus() && position === null || position === false) {
|
|
617
|
+
return true;
|
|
618
|
+
}
|
|
619
|
+
if (dispatch && position === null && !isTextSelection(editor.state.selection)) {
|
|
620
|
+
delayedFocus();
|
|
621
|
+
return true;
|
|
622
|
+
}
|
|
623
|
+
const selection = resolveFocusPosition(tr.doc, position) || editor.state.selection;
|
|
624
|
+
const isSameSelection = editor.state.selection.eq(selection);
|
|
625
|
+
if (dispatch) {
|
|
626
|
+
if (!isSameSelection) {
|
|
627
|
+
tr.setSelection(selection);
|
|
628
|
+
}
|
|
629
|
+
if (isSameSelection && tr.storedMarks) {
|
|
630
|
+
tr.setStoredMarks(tr.storedMarks);
|
|
631
|
+
}
|
|
632
|
+
delayedFocus();
|
|
633
|
+
}
|
|
634
|
+
return true;
|
|
635
|
+
};
|
|
636
|
+
var forEach = (items, fn) => (props) => {
|
|
637
|
+
return items.every((item, index) => fn(item, { ...props, index }));
|
|
638
|
+
};
|
|
639
|
+
var insertContent = (value, options) => ({ tr, commands }) => {
|
|
640
|
+
return commands.insertContentAt({ from: tr.selection.from, to: tr.selection.to }, value, options);
|
|
641
|
+
};
|
|
642
|
+
var removeWhitespaces = (node) => {
|
|
643
|
+
const children = node.childNodes;
|
|
644
|
+
for (let i = children.length - 1; i >= 0; i -= 1) {
|
|
645
|
+
const child = children[i];
|
|
646
|
+
if (child.nodeType === 3 && child.nodeValue && /^(\n\s\s|\n)$/.test(child.nodeValue)) {
|
|
647
|
+
node.removeChild(child);
|
|
648
|
+
} else if (child.nodeType === 1) {
|
|
649
|
+
removeWhitespaces(child);
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
return node;
|
|
653
|
+
};
|
|
654
|
+
function elementFromString(value) {
|
|
655
|
+
if (typeof window === "undefined") {
|
|
656
|
+
throw new Error("[tiptap error]: there is no window object available, so this function cannot be used");
|
|
657
|
+
}
|
|
658
|
+
const wrappedValue = `<body>${value}</body>`;
|
|
659
|
+
const html = new window.DOMParser().parseFromString(wrappedValue, "text/html").body;
|
|
660
|
+
return removeWhitespaces(html);
|
|
661
|
+
}
|
|
662
|
+
function createNodeFromContent(content, schema, options) {
|
|
663
|
+
if (content instanceof import_model2.Node || content instanceof import_model2.Fragment) {
|
|
664
|
+
return content;
|
|
665
|
+
}
|
|
666
|
+
options = {
|
|
667
|
+
slice: true,
|
|
668
|
+
parseOptions: {},
|
|
669
|
+
...options
|
|
670
|
+
};
|
|
671
|
+
const isJSONContent = typeof content === "object" && content !== null;
|
|
672
|
+
const isTextContent = typeof content === "string";
|
|
673
|
+
if (isJSONContent) {
|
|
674
|
+
try {
|
|
675
|
+
const isArrayContent = Array.isArray(content) && content.length > 0;
|
|
676
|
+
if (isArrayContent) {
|
|
677
|
+
return import_model2.Fragment.fromArray(content.map((item) => schema.nodeFromJSON(item)));
|
|
678
|
+
}
|
|
679
|
+
const node = schema.nodeFromJSON(content);
|
|
680
|
+
if (options.errorOnInvalidContent) {
|
|
681
|
+
node.check();
|
|
682
|
+
}
|
|
683
|
+
return node;
|
|
684
|
+
} catch (error) {
|
|
685
|
+
if (options.errorOnInvalidContent) {
|
|
686
|
+
throw new Error("[tiptap error]: Invalid JSON content", { cause: error });
|
|
687
|
+
}
|
|
688
|
+
console.warn("[tiptap warn]: Invalid content.", "Passed value:", content, "Error:", error);
|
|
689
|
+
return createNodeFromContent("", schema, options);
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
if (isTextContent) {
|
|
693
|
+
if (options.errorOnInvalidContent) {
|
|
694
|
+
let hasInvalidContent = false;
|
|
695
|
+
let invalidContent = "";
|
|
696
|
+
const contentCheckSchema = new import_model2.Schema({
|
|
697
|
+
topNode: schema.spec.topNode,
|
|
698
|
+
marks: schema.spec.marks,
|
|
699
|
+
// Prosemirror's schemas are executed such that: the last to execute, matches last
|
|
700
|
+
// This means that we can add a catch-all node at the end of the schema to catch any content that we don't know how to handle
|
|
701
|
+
nodes: schema.spec.nodes.append({
|
|
702
|
+
__tiptap__private__unknown__catch__all__node: {
|
|
703
|
+
content: "inline*",
|
|
704
|
+
group: "block",
|
|
705
|
+
parseDOM: [
|
|
706
|
+
{
|
|
707
|
+
tag: "*",
|
|
708
|
+
getAttrs: (e) => {
|
|
709
|
+
hasInvalidContent = true;
|
|
710
|
+
invalidContent = typeof e === "string" ? e : e.outerHTML;
|
|
711
|
+
return null;
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
]
|
|
715
|
+
}
|
|
716
|
+
})
|
|
717
|
+
});
|
|
718
|
+
if (options.slice) {
|
|
719
|
+
import_model2.DOMParser.fromSchema(contentCheckSchema).parseSlice(elementFromString(content), options.parseOptions);
|
|
720
|
+
} else {
|
|
721
|
+
import_model2.DOMParser.fromSchema(contentCheckSchema).parse(elementFromString(content), options.parseOptions);
|
|
722
|
+
}
|
|
723
|
+
if (options.errorOnInvalidContent && hasInvalidContent) {
|
|
724
|
+
throw new Error("[tiptap error]: Invalid HTML content", {
|
|
725
|
+
cause: new Error(`Invalid element found: ${invalidContent}`)
|
|
726
|
+
});
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
const parser = import_model2.DOMParser.fromSchema(schema);
|
|
730
|
+
if (options.slice) {
|
|
731
|
+
return parser.parseSlice(elementFromString(content), options.parseOptions).content;
|
|
732
|
+
}
|
|
733
|
+
return parser.parse(elementFromString(content), options.parseOptions);
|
|
734
|
+
}
|
|
735
|
+
return createNodeFromContent("", schema, options);
|
|
736
|
+
}
|
|
737
|
+
function selectionToInsertionEnd(tr, startLen, bias) {
|
|
738
|
+
const last = tr.steps.length - 1;
|
|
739
|
+
if (last < startLen) {
|
|
740
|
+
return;
|
|
741
|
+
}
|
|
742
|
+
const step = tr.steps[last];
|
|
743
|
+
if (!(step instanceof import_transform2.ReplaceStep || step instanceof import_transform2.ReplaceAroundStep)) {
|
|
744
|
+
return;
|
|
745
|
+
}
|
|
746
|
+
const map = tr.mapping.maps[last];
|
|
747
|
+
let end = 0;
|
|
748
|
+
map.forEach((_from, _to, _newFrom, newTo) => {
|
|
749
|
+
if (end === 0) {
|
|
750
|
+
end = newTo;
|
|
751
|
+
}
|
|
752
|
+
});
|
|
753
|
+
tr.setSelection(import_state5.Selection.near(tr.doc.resolve(end), bias));
|
|
754
|
+
}
|
|
755
|
+
var isFragment = (nodeOrFragment) => {
|
|
756
|
+
return !("type" in nodeOrFragment);
|
|
757
|
+
};
|
|
758
|
+
var insertContentAt = (position, value, options) => ({ tr, dispatch, editor }) => {
|
|
759
|
+
var _a;
|
|
760
|
+
if (dispatch) {
|
|
761
|
+
options = {
|
|
762
|
+
parseOptions: editor.options.parseOptions,
|
|
763
|
+
updateSelection: true,
|
|
764
|
+
applyInputRules: false,
|
|
765
|
+
applyPasteRules: false,
|
|
766
|
+
...options
|
|
767
|
+
};
|
|
768
|
+
let content;
|
|
769
|
+
const emitContentError = (error) => {
|
|
770
|
+
editor.emit("contentError", {
|
|
771
|
+
editor,
|
|
772
|
+
error,
|
|
773
|
+
disableCollaboration: () => {
|
|
774
|
+
if ("collaboration" in editor.storage && typeof editor.storage.collaboration === "object" && editor.storage.collaboration) {
|
|
775
|
+
;
|
|
776
|
+
editor.storage.collaboration.isDisabled = true;
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
});
|
|
780
|
+
};
|
|
781
|
+
const parseOptions = {
|
|
782
|
+
preserveWhitespace: "full",
|
|
783
|
+
...options.parseOptions
|
|
784
|
+
};
|
|
785
|
+
if (!options.errorOnInvalidContent && !editor.options.enableContentCheck && editor.options.emitContentError) {
|
|
786
|
+
try {
|
|
787
|
+
createNodeFromContent(value, editor.schema, {
|
|
788
|
+
parseOptions,
|
|
789
|
+
errorOnInvalidContent: true
|
|
790
|
+
});
|
|
791
|
+
} catch (e) {
|
|
792
|
+
emitContentError(e);
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
try {
|
|
796
|
+
content = createNodeFromContent(value, editor.schema, {
|
|
797
|
+
parseOptions,
|
|
798
|
+
errorOnInvalidContent: (_a = options.errorOnInvalidContent) != null ? _a : editor.options.enableContentCheck
|
|
799
|
+
});
|
|
800
|
+
} catch (e) {
|
|
801
|
+
emitContentError(e);
|
|
802
|
+
return false;
|
|
803
|
+
}
|
|
804
|
+
let { from, to } = typeof position === "number" ? { from: position, to: position } : { from: position.from, to: position.to };
|
|
805
|
+
let isOnlyTextContent = true;
|
|
806
|
+
let isOnlyBlockContent = true;
|
|
807
|
+
const nodes = isFragment(content) ? content : [content];
|
|
808
|
+
nodes.forEach((node) => {
|
|
809
|
+
node.check();
|
|
810
|
+
isOnlyTextContent = isOnlyTextContent ? node.isText && node.marks.length === 0 : false;
|
|
811
|
+
isOnlyBlockContent = isOnlyBlockContent ? node.isBlock : false;
|
|
812
|
+
});
|
|
813
|
+
if (from === to && isOnlyBlockContent) {
|
|
814
|
+
const { parent } = tr.doc.resolve(from);
|
|
815
|
+
const isEmptyTextBlock = parent.isTextblock && !parent.type.spec.code && !parent.childCount;
|
|
816
|
+
if (isEmptyTextBlock) {
|
|
817
|
+
from -= 1;
|
|
818
|
+
to += 1;
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
let newContent;
|
|
822
|
+
if (isOnlyTextContent) {
|
|
823
|
+
if (Array.isArray(value)) {
|
|
824
|
+
newContent = value.map((v) => v.text || "").join("");
|
|
825
|
+
} else if (value instanceof import_model.Fragment) {
|
|
826
|
+
let text = "";
|
|
827
|
+
value.forEach((node) => {
|
|
828
|
+
if (node.text) {
|
|
829
|
+
text += node.text;
|
|
830
|
+
}
|
|
831
|
+
});
|
|
832
|
+
newContent = text;
|
|
833
|
+
} else if (typeof value === "object" && !!value && !!value.text) {
|
|
834
|
+
newContent = value.text;
|
|
835
|
+
} else {
|
|
836
|
+
newContent = value;
|
|
837
|
+
}
|
|
838
|
+
tr.insertText(newContent, from, to);
|
|
839
|
+
} else {
|
|
840
|
+
newContent = content;
|
|
841
|
+
const $from = tr.doc.resolve(from);
|
|
842
|
+
const $fromNode = $from.node();
|
|
843
|
+
const fromSelectionAtStart = $from.parentOffset === 0;
|
|
844
|
+
const isTextSelection2 = $fromNode.isText || $fromNode.isTextblock;
|
|
845
|
+
const hasContent = $fromNode.content.size > 0;
|
|
846
|
+
if (fromSelectionAtStart && isTextSelection2 && hasContent) {
|
|
847
|
+
from = Math.max(0, from - 1);
|
|
848
|
+
}
|
|
849
|
+
tr.replaceWith(from, to, newContent);
|
|
850
|
+
}
|
|
851
|
+
if (options.updateSelection) {
|
|
852
|
+
selectionToInsertionEnd(tr, tr.steps.length - 1, -1);
|
|
853
|
+
}
|
|
854
|
+
if (options.applyInputRules) {
|
|
855
|
+
tr.setMeta("applyInputRules", { from, text: newContent });
|
|
856
|
+
}
|
|
857
|
+
if (options.applyPasteRules) {
|
|
858
|
+
tr.setMeta("applyPasteRules", { from, text: newContent });
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
return true;
|
|
862
|
+
};
|
|
863
|
+
var joinUp = () => ({ state, dispatch }) => {
|
|
864
|
+
return (0, import_commands4.joinUp)(state, dispatch);
|
|
865
|
+
};
|
|
866
|
+
var joinDown = () => ({ state, dispatch }) => {
|
|
867
|
+
return (0, import_commands4.joinDown)(state, dispatch);
|
|
868
|
+
};
|
|
869
|
+
var joinBackward = () => ({ state, dispatch }) => {
|
|
870
|
+
return (0, import_commands4.joinBackward)(state, dispatch);
|
|
871
|
+
};
|
|
872
|
+
var joinForward = () => ({ state, dispatch }) => {
|
|
873
|
+
return (0, import_commands4.joinForward)(state, dispatch);
|
|
874
|
+
};
|
|
875
|
+
var joinItemBackward = () => ({ state, dispatch, tr }) => {
|
|
876
|
+
try {
|
|
877
|
+
const point = (0, import_transform3.joinPoint)(state.doc, state.selection.$from.pos, -1);
|
|
878
|
+
if (point === null || point === void 0) {
|
|
879
|
+
return false;
|
|
880
|
+
}
|
|
881
|
+
tr.join(point, 2);
|
|
882
|
+
if (dispatch) {
|
|
883
|
+
dispatch(tr);
|
|
884
|
+
}
|
|
885
|
+
return true;
|
|
886
|
+
} catch {
|
|
887
|
+
return false;
|
|
888
|
+
}
|
|
889
|
+
};
|
|
890
|
+
var joinItemForward = () => ({ state, dispatch, tr }) => {
|
|
891
|
+
try {
|
|
892
|
+
const point = (0, import_transform4.joinPoint)(state.doc, state.selection.$from.pos, 1);
|
|
893
|
+
if (point === null || point === void 0) {
|
|
894
|
+
return false;
|
|
895
|
+
}
|
|
896
|
+
tr.join(point, 2);
|
|
897
|
+
if (dispatch) {
|
|
898
|
+
dispatch(tr);
|
|
899
|
+
}
|
|
900
|
+
return true;
|
|
901
|
+
} catch {
|
|
902
|
+
return false;
|
|
903
|
+
}
|
|
904
|
+
};
|
|
905
|
+
var joinTextblockBackward = () => ({ state, dispatch }) => {
|
|
906
|
+
return (0, import_commands5.joinTextblockBackward)(state, dispatch);
|
|
907
|
+
};
|
|
908
|
+
var joinTextblockForward = () => ({ state, dispatch }) => {
|
|
909
|
+
return (0, import_commands6.joinTextblockForward)(state, dispatch);
|
|
910
|
+
};
|
|
911
|
+
function isMacOS() {
|
|
912
|
+
return typeof navigator !== "undefined" ? /Mac/.test(navigator.platform) : false;
|
|
913
|
+
}
|
|
914
|
+
function normalizeKeyName(name) {
|
|
915
|
+
const parts = name.split(/-(?!$)/);
|
|
916
|
+
let result = parts[parts.length - 1];
|
|
917
|
+
if (result === "Space") {
|
|
918
|
+
result = " ";
|
|
919
|
+
}
|
|
920
|
+
let alt;
|
|
921
|
+
let ctrl;
|
|
922
|
+
let shift;
|
|
923
|
+
let meta;
|
|
924
|
+
for (let i = 0; i < parts.length - 1; i += 1) {
|
|
925
|
+
const mod = parts[i];
|
|
926
|
+
if (/^(cmd|meta|m)$/i.test(mod)) {
|
|
927
|
+
meta = true;
|
|
928
|
+
} else if (/^a(lt)?$/i.test(mod)) {
|
|
929
|
+
alt = true;
|
|
930
|
+
} else if (/^(c|ctrl|control)$/i.test(mod)) {
|
|
931
|
+
ctrl = true;
|
|
932
|
+
} else if (/^s(hift)?$/i.test(mod)) {
|
|
933
|
+
shift = true;
|
|
934
|
+
} else if (/^mod$/i.test(mod)) {
|
|
935
|
+
if (isiOS() || isMacOS()) {
|
|
936
|
+
meta = true;
|
|
937
|
+
} else {
|
|
938
|
+
ctrl = true;
|
|
939
|
+
}
|
|
940
|
+
} else {
|
|
941
|
+
throw new Error(`Unrecognized modifier name: ${mod}`);
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
if (alt) {
|
|
945
|
+
result = `Alt-${result}`;
|
|
946
|
+
}
|
|
947
|
+
if (ctrl) {
|
|
948
|
+
result = `Ctrl-${result}`;
|
|
949
|
+
}
|
|
950
|
+
if (meta) {
|
|
951
|
+
result = `Meta-${result}`;
|
|
952
|
+
}
|
|
953
|
+
if (shift) {
|
|
954
|
+
result = `Shift-${result}`;
|
|
955
|
+
}
|
|
956
|
+
return result;
|
|
957
|
+
}
|
|
958
|
+
var keyboardShortcut = (name) => ({ editor, view, tr, dispatch }) => {
|
|
959
|
+
const keys = normalizeKeyName(name).split(/-(?!$)/);
|
|
960
|
+
const key = keys.find((item) => !["Alt", "Ctrl", "Meta", "Shift"].includes(item));
|
|
961
|
+
const event = new KeyboardEvent("keydown", {
|
|
962
|
+
key: key === "Space" ? " " : key,
|
|
963
|
+
altKey: keys.includes("Alt"),
|
|
964
|
+
ctrlKey: keys.includes("Ctrl"),
|
|
965
|
+
metaKey: keys.includes("Meta"),
|
|
966
|
+
shiftKey: keys.includes("Shift"),
|
|
967
|
+
bubbles: true,
|
|
968
|
+
cancelable: true
|
|
969
|
+
});
|
|
970
|
+
const capturedTransaction = editor.captureTransaction(() => {
|
|
971
|
+
view.someProp("handleKeyDown", (f) => f(view, event));
|
|
972
|
+
});
|
|
973
|
+
capturedTransaction == null ? void 0 : capturedTransaction.steps.forEach((step) => {
|
|
974
|
+
const newStep = step.map(tr.mapping);
|
|
975
|
+
if (newStep && dispatch) {
|
|
976
|
+
tr.maybeStep(newStep);
|
|
977
|
+
}
|
|
978
|
+
});
|
|
979
|
+
return true;
|
|
980
|
+
};
|
|
981
|
+
function isNodeActive(state, typeOrName, attributes = {}) {
|
|
982
|
+
const { from, to, empty } = state.selection;
|
|
983
|
+
const type = typeOrName ? getNodeType(typeOrName, state.schema) : null;
|
|
984
|
+
const nodeRanges = [];
|
|
985
|
+
state.doc.nodesBetween(from, to, (node, pos) => {
|
|
986
|
+
if (node.isText) {
|
|
987
|
+
return;
|
|
988
|
+
}
|
|
989
|
+
const relativeFrom = Math.max(from, pos);
|
|
990
|
+
const relativeTo = Math.min(to, pos + node.nodeSize);
|
|
991
|
+
nodeRanges.push({
|
|
992
|
+
node,
|
|
993
|
+
from: relativeFrom,
|
|
994
|
+
to: relativeTo
|
|
995
|
+
});
|
|
996
|
+
});
|
|
997
|
+
const selectionRange = to - from;
|
|
998
|
+
const matchedNodeRanges = nodeRanges.filter((nodeRange) => {
|
|
999
|
+
if (!type) {
|
|
1000
|
+
return true;
|
|
1001
|
+
}
|
|
1002
|
+
return type.name === nodeRange.node.type.name;
|
|
1003
|
+
}).filter((nodeRange) => objectIncludes(nodeRange.node.attrs, attributes, { strict: false }));
|
|
1004
|
+
if (empty) {
|
|
1005
|
+
return !!matchedNodeRanges.length;
|
|
1006
|
+
}
|
|
1007
|
+
const range = matchedNodeRanges.reduce((sum, nodeRange) => sum + nodeRange.to - nodeRange.from, 0);
|
|
1008
|
+
return range >= selectionRange;
|
|
1009
|
+
}
|
|
1010
|
+
var lift = (typeOrName, attributes = {}) => ({ state, dispatch }) => {
|
|
1011
|
+
const type = getNodeType(typeOrName, state.schema);
|
|
1012
|
+
const isActive2 = isNodeActive(state, type, attributes);
|
|
1013
|
+
if (!isActive2) {
|
|
1014
|
+
return false;
|
|
1015
|
+
}
|
|
1016
|
+
return (0, import_commands7.lift)(state, dispatch);
|
|
1017
|
+
};
|
|
1018
|
+
var liftEmptyBlock = () => ({ state, dispatch }) => {
|
|
1019
|
+
return (0, import_commands8.liftEmptyBlock)(state, dispatch);
|
|
1020
|
+
};
|
|
1021
|
+
var liftListItem = (typeOrName) => ({ state, dispatch }) => {
|
|
1022
|
+
const type = getNodeType(typeOrName, state.schema);
|
|
1023
|
+
return (0, import_schema_list.liftListItem)(type)(state, dispatch);
|
|
1024
|
+
};
|
|
1025
|
+
var newlineInCode = () => ({ state, dispatch }) => {
|
|
1026
|
+
return (0, import_commands9.newlineInCode)(state, dispatch);
|
|
1027
|
+
};
|
|
1028
|
+
function getSchemaTypeNameByName(name, schema) {
|
|
1029
|
+
if (schema.nodes[name]) {
|
|
1030
|
+
return "node";
|
|
1031
|
+
}
|
|
1032
|
+
if (schema.marks[name]) {
|
|
1033
|
+
return "mark";
|
|
1034
|
+
}
|
|
1035
|
+
return null;
|
|
1036
|
+
}
|
|
1037
|
+
function deleteProps(obj, propOrProps) {
|
|
1038
|
+
const props = typeof propOrProps === "string" ? [propOrProps] : propOrProps;
|
|
1039
|
+
return Object.keys(obj).reduce((newObj, prop) => {
|
|
1040
|
+
if (!props.includes(prop)) {
|
|
1041
|
+
newObj[prop] = obj[prop];
|
|
1042
|
+
}
|
|
1043
|
+
return newObj;
|
|
1044
|
+
}, {});
|
|
1045
|
+
}
|
|
1046
|
+
var resetAttributes = (typeOrName, attributes) => ({ tr, state, dispatch }) => {
|
|
1047
|
+
let nodeType = null;
|
|
1048
|
+
let markType = null;
|
|
1049
|
+
const schemaType = getSchemaTypeNameByName(
|
|
1050
|
+
typeof typeOrName === "string" ? typeOrName : typeOrName.name,
|
|
1051
|
+
state.schema
|
|
1052
|
+
);
|
|
1053
|
+
if (!schemaType) {
|
|
1054
|
+
return false;
|
|
1055
|
+
}
|
|
1056
|
+
if (schemaType === "node") {
|
|
1057
|
+
nodeType = getNodeType(typeOrName, state.schema);
|
|
1058
|
+
}
|
|
1059
|
+
if (schemaType === "mark") {
|
|
1060
|
+
markType = getMarkType(typeOrName, state.schema);
|
|
1061
|
+
}
|
|
1062
|
+
let canReset = false;
|
|
1063
|
+
tr.selection.ranges.forEach((range) => {
|
|
1064
|
+
state.doc.nodesBetween(range.$from.pos, range.$to.pos, (node, pos) => {
|
|
1065
|
+
if (nodeType && nodeType === node.type) {
|
|
1066
|
+
canReset = true;
|
|
1067
|
+
if (dispatch) {
|
|
1068
|
+
tr.setNodeMarkup(pos, void 0, deleteProps(node.attrs, attributes));
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
if (markType && node.marks.length) {
|
|
1072
|
+
node.marks.forEach((mark) => {
|
|
1073
|
+
if (markType === mark.type) {
|
|
1074
|
+
canReset = true;
|
|
1075
|
+
if (dispatch) {
|
|
1076
|
+
tr.addMark(pos, pos + node.nodeSize, markType.create(deleteProps(mark.attrs, attributes)));
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
});
|
|
1080
|
+
}
|
|
1081
|
+
});
|
|
1082
|
+
});
|
|
1083
|
+
return canReset;
|
|
1084
|
+
};
|
|
1085
|
+
var scrollIntoView = () => ({ tr, dispatch }) => {
|
|
1086
|
+
if (dispatch) {
|
|
1087
|
+
tr.scrollIntoView();
|
|
1088
|
+
}
|
|
1089
|
+
return true;
|
|
1090
|
+
};
|
|
1091
|
+
var selectAll = () => ({ tr, dispatch }) => {
|
|
1092
|
+
if (dispatch) {
|
|
1093
|
+
const selection = new import_state6.AllSelection(tr.doc);
|
|
1094
|
+
tr.setSelection(selection);
|
|
1095
|
+
}
|
|
1096
|
+
return true;
|
|
1097
|
+
};
|
|
1098
|
+
var selectNodeBackward = () => ({ state, dispatch }) => {
|
|
1099
|
+
return (0, import_commands10.selectNodeBackward)(state, dispatch);
|
|
1100
|
+
};
|
|
1101
|
+
var selectNodeForward = () => ({ state, dispatch }) => {
|
|
1102
|
+
return (0, import_commands11.selectNodeForward)(state, dispatch);
|
|
1103
|
+
};
|
|
1104
|
+
var selectParentNode = () => ({ state, dispatch }) => {
|
|
1105
|
+
return (0, import_commands12.selectParentNode)(state, dispatch);
|
|
1106
|
+
};
|
|
1107
|
+
var selectTextblockEnd = () => ({ state, dispatch }) => {
|
|
1108
|
+
return (0, import_commands13.selectTextblockEnd)(state, dispatch);
|
|
1109
|
+
};
|
|
1110
|
+
var selectTextblockStart = () => ({ state, dispatch }) => {
|
|
1111
|
+
return (0, import_commands14.selectTextblockStart)(state, dispatch);
|
|
1112
|
+
};
|
|
1113
|
+
function createDocument(content, schema, parseOptions = {}, options = {}) {
|
|
1114
|
+
return createNodeFromContent(content, schema, {
|
|
1115
|
+
slice: false,
|
|
1116
|
+
parseOptions,
|
|
1117
|
+
errorOnInvalidContent: options.errorOnInvalidContent
|
|
1118
|
+
});
|
|
1119
|
+
}
|
|
1120
|
+
var setContent = (content, { errorOnInvalidContent, emitUpdate = true, parseOptions = {} } = {}) => ({ editor, tr, dispatch, commands }) => {
|
|
1121
|
+
const { doc } = tr;
|
|
1122
|
+
if (parseOptions.preserveWhitespace !== "full") {
|
|
1123
|
+
const document2 = createDocument(content, editor.schema, parseOptions, {
|
|
1124
|
+
errorOnInvalidContent: errorOnInvalidContent != null ? errorOnInvalidContent : editor.options.enableContentCheck
|
|
1125
|
+
});
|
|
1126
|
+
if (dispatch) {
|
|
1127
|
+
tr.replaceWith(0, doc.content.size, document2).setMeta("preventUpdate", !emitUpdate);
|
|
1128
|
+
}
|
|
1129
|
+
return true;
|
|
1130
|
+
}
|
|
1131
|
+
if (dispatch) {
|
|
1132
|
+
tr.setMeta("preventUpdate", !emitUpdate);
|
|
1133
|
+
}
|
|
1134
|
+
return commands.insertContentAt({ from: 0, to: doc.content.size }, content, {
|
|
1135
|
+
parseOptions,
|
|
1136
|
+
errorOnInvalidContent: errorOnInvalidContent != null ? errorOnInvalidContent : editor.options.enableContentCheck
|
|
1137
|
+
});
|
|
1138
|
+
};
|
|
1139
|
+
function getMarkAttributes(state, typeOrName) {
|
|
1140
|
+
const type = getMarkType(typeOrName, state.schema);
|
|
1141
|
+
const { from, to, empty } = state.selection;
|
|
1142
|
+
const marks = [];
|
|
1143
|
+
if (empty) {
|
|
1144
|
+
if (state.storedMarks) {
|
|
1145
|
+
marks.push(...state.storedMarks);
|
|
1146
|
+
}
|
|
1147
|
+
marks.push(...state.selection.$head.marks());
|
|
1148
|
+
} else {
|
|
1149
|
+
state.doc.nodesBetween(from, to, (node) => {
|
|
1150
|
+
marks.push(...node.marks);
|
|
1151
|
+
});
|
|
1152
|
+
}
|
|
1153
|
+
const mark = marks.find((markItem) => markItem.type.name === type.name);
|
|
1154
|
+
if (!mark) {
|
|
1155
|
+
return {};
|
|
1156
|
+
}
|
|
1157
|
+
return { ...mark.attrs };
|
|
1158
|
+
}
|
|
1159
|
+
function combineTransactionSteps(oldDoc, transactions) {
|
|
1160
|
+
const transform = new import_transform5.Transform(oldDoc);
|
|
1161
|
+
transactions.forEach((transaction) => {
|
|
1162
|
+
transaction.steps.forEach((step) => {
|
|
1163
|
+
transform.step(step);
|
|
1164
|
+
});
|
|
1165
|
+
});
|
|
1166
|
+
return transform;
|
|
1167
|
+
}
|
|
1168
|
+
function defaultBlockAt(match) {
|
|
1169
|
+
for (let i = 0; i < match.edgeCount; i += 1) {
|
|
1170
|
+
const { type } = match.edge(i);
|
|
1171
|
+
if (type.isTextblock && !type.hasRequiredAttrs()) {
|
|
1172
|
+
return type;
|
|
1173
|
+
}
|
|
1174
|
+
}
|
|
1175
|
+
return null;
|
|
1176
|
+
}
|
|
1177
|
+
function findParentNodeClosestToPos($pos, predicate) {
|
|
1178
|
+
for (let i = $pos.depth; i > 0; i -= 1) {
|
|
1179
|
+
const node = $pos.node(i);
|
|
1180
|
+
if (predicate(node)) {
|
|
1181
|
+
return {
|
|
1182
|
+
pos: i > 0 ? $pos.before(i) : 0,
|
|
1183
|
+
start: $pos.start(i),
|
|
1184
|
+
depth: i,
|
|
1185
|
+
node
|
|
1186
|
+
};
|
|
1187
|
+
}
|
|
1188
|
+
}
|
|
1189
|
+
}
|
|
1190
|
+
function findParentNode(predicate) {
|
|
1191
|
+
return (selection) => findParentNodeClosestToPos(selection.$from, predicate);
|
|
1192
|
+
}
|
|
1193
|
+
function getExtensionField(extension, field, context) {
|
|
1194
|
+
if (extension.config[field] === void 0 && extension.parent) {
|
|
1195
|
+
return getExtensionField(extension.parent, field, context);
|
|
1196
|
+
}
|
|
1197
|
+
if (typeof extension.config[field] === "function") {
|
|
1198
|
+
const value = extension.config[field].bind({
|
|
1199
|
+
...context,
|
|
1200
|
+
parent: extension.parent ? getExtensionField(extension.parent, field, context) : null
|
|
1201
|
+
});
|
|
1202
|
+
return value;
|
|
1203
|
+
}
|
|
1204
|
+
return extension.config[field];
|
|
1205
|
+
}
|
|
1206
|
+
function flattenExtensions(extensions) {
|
|
1207
|
+
return extensions.map((extension) => {
|
|
1208
|
+
const context = {
|
|
1209
|
+
name: extension.name,
|
|
1210
|
+
options: extension.options,
|
|
1211
|
+
storage: extension.storage
|
|
1212
|
+
};
|
|
1213
|
+
const addExtensions = getExtensionField(extension, "addExtensions", context);
|
|
1214
|
+
if (addExtensions) {
|
|
1215
|
+
return [extension, ...flattenExtensions(addExtensions())];
|
|
1216
|
+
}
|
|
1217
|
+
return extension;
|
|
1218
|
+
}).flat(10);
|
|
1219
|
+
}
|
|
1220
|
+
function getHTMLFromFragment(fragment, schema) {
|
|
1221
|
+
const documentFragment = import_model4.DOMSerializer.fromSchema(schema).serializeFragment(fragment);
|
|
1222
|
+
const temporaryDocument = document.implementation.createHTMLDocument();
|
|
1223
|
+
const container = temporaryDocument.createElement("div");
|
|
1224
|
+
container.appendChild(documentFragment);
|
|
1225
|
+
return container.innerHTML;
|
|
1226
|
+
}
|
|
1227
|
+
function isFunction(value) {
|
|
1228
|
+
return typeof value === "function";
|
|
1229
|
+
}
|
|
1230
|
+
function callOrReturn(value, context = void 0, ...props) {
|
|
1231
|
+
if (isFunction(value)) {
|
|
1232
|
+
if (context) {
|
|
1233
|
+
return value.bind(context)(...props);
|
|
1234
|
+
}
|
|
1235
|
+
return value(...props);
|
|
1236
|
+
}
|
|
1237
|
+
return value;
|
|
1238
|
+
}
|
|
1239
|
+
function isEmptyObject(value = {}) {
|
|
1240
|
+
return Object.keys(value).length === 0 && value.constructor === Object;
|
|
1241
|
+
}
|
|
1242
|
+
function splitExtensions(extensions) {
|
|
1243
|
+
const baseExtensions = extensions.filter((extension) => extension.type === "extension");
|
|
1244
|
+
const nodeExtensions = extensions.filter((extension) => extension.type === "node");
|
|
1245
|
+
const markExtensions = extensions.filter((extension) => extension.type === "mark");
|
|
1246
|
+
return {
|
|
1247
|
+
baseExtensions,
|
|
1248
|
+
nodeExtensions,
|
|
1249
|
+
markExtensions
|
|
1250
|
+
};
|
|
1251
|
+
}
|
|
1252
|
+
function getAttributesFromExtensions(extensions) {
|
|
1253
|
+
const extensionAttributes = [];
|
|
1254
|
+
const { nodeExtensions, markExtensions } = splitExtensions(extensions);
|
|
1255
|
+
const nodeAndMarkExtensions = [...nodeExtensions, ...markExtensions];
|
|
1256
|
+
const defaultAttribute = {
|
|
1257
|
+
default: null,
|
|
1258
|
+
validate: void 0,
|
|
1259
|
+
rendered: true,
|
|
1260
|
+
renderHTML: null,
|
|
1261
|
+
parseHTML: null,
|
|
1262
|
+
keepOnSplit: true,
|
|
1263
|
+
isRequired: false
|
|
1264
|
+
};
|
|
1265
|
+
extensions.forEach((extension) => {
|
|
1266
|
+
const context = {
|
|
1267
|
+
name: extension.name,
|
|
1268
|
+
options: extension.options,
|
|
1269
|
+
storage: extension.storage,
|
|
1270
|
+
extensions: nodeAndMarkExtensions
|
|
1271
|
+
};
|
|
1272
|
+
const addGlobalAttributes = getExtensionField(
|
|
1273
|
+
extension,
|
|
1274
|
+
"addGlobalAttributes",
|
|
1275
|
+
context
|
|
1276
|
+
);
|
|
1277
|
+
if (!addGlobalAttributes) {
|
|
1278
|
+
return;
|
|
1279
|
+
}
|
|
1280
|
+
const globalAttributes = addGlobalAttributes();
|
|
1281
|
+
globalAttributes.forEach((globalAttribute) => {
|
|
1282
|
+
globalAttribute.types.forEach((type) => {
|
|
1283
|
+
Object.entries(globalAttribute.attributes).forEach(([name, attribute]) => {
|
|
1284
|
+
extensionAttributes.push({
|
|
1285
|
+
type,
|
|
1286
|
+
name,
|
|
1287
|
+
attribute: {
|
|
1288
|
+
...defaultAttribute,
|
|
1289
|
+
...attribute
|
|
1290
|
+
}
|
|
1291
|
+
});
|
|
1292
|
+
});
|
|
1293
|
+
});
|
|
1294
|
+
});
|
|
1295
|
+
});
|
|
1296
|
+
nodeAndMarkExtensions.forEach((extension) => {
|
|
1297
|
+
const context = {
|
|
1298
|
+
name: extension.name,
|
|
1299
|
+
options: extension.options,
|
|
1300
|
+
storage: extension.storage
|
|
1301
|
+
};
|
|
1302
|
+
const addAttributes = getExtensionField(
|
|
1303
|
+
extension,
|
|
1304
|
+
"addAttributes",
|
|
1305
|
+
context
|
|
1306
|
+
);
|
|
1307
|
+
if (!addAttributes) {
|
|
1308
|
+
return;
|
|
1309
|
+
}
|
|
1310
|
+
const attributes = addAttributes();
|
|
1311
|
+
Object.entries(attributes).forEach(([name, attribute]) => {
|
|
1312
|
+
const mergedAttr = {
|
|
1313
|
+
...defaultAttribute,
|
|
1314
|
+
...attribute
|
|
1315
|
+
};
|
|
1316
|
+
if (typeof (mergedAttr == null ? void 0 : mergedAttr.default) === "function") {
|
|
1317
|
+
mergedAttr.default = mergedAttr.default();
|
|
1318
|
+
}
|
|
1319
|
+
if ((mergedAttr == null ? void 0 : mergedAttr.isRequired) && (mergedAttr == null ? void 0 : mergedAttr.default) === void 0) {
|
|
1320
|
+
delete mergedAttr.default;
|
|
1321
|
+
}
|
|
1322
|
+
extensionAttributes.push({
|
|
1323
|
+
type: extension.name,
|
|
1324
|
+
name,
|
|
1325
|
+
attribute: mergedAttr
|
|
1326
|
+
});
|
|
1327
|
+
});
|
|
1328
|
+
});
|
|
1329
|
+
return extensionAttributes;
|
|
1330
|
+
}
|
|
1331
|
+
function mergeAttributes(...objects) {
|
|
1332
|
+
return objects.filter((item) => !!item).reduce((items, item) => {
|
|
1333
|
+
const mergedAttributes = { ...items };
|
|
1334
|
+
Object.entries(item).forEach(([key, value]) => {
|
|
1335
|
+
const exists = mergedAttributes[key];
|
|
1336
|
+
if (!exists) {
|
|
1337
|
+
mergedAttributes[key] = value;
|
|
1338
|
+
return;
|
|
1339
|
+
}
|
|
1340
|
+
if (key === "class") {
|
|
1341
|
+
const valueClasses = value ? String(value).split(" ") : [];
|
|
1342
|
+
const existingClasses = mergedAttributes[key] ? mergedAttributes[key].split(" ") : [];
|
|
1343
|
+
const insertClasses = valueClasses.filter((valueClass) => !existingClasses.includes(valueClass));
|
|
1344
|
+
mergedAttributes[key] = [...existingClasses, ...insertClasses].join(" ");
|
|
1345
|
+
} else if (key === "style") {
|
|
1346
|
+
const newStyles = value ? value.split(";").map((style2) => style2.trim()).filter(Boolean) : [];
|
|
1347
|
+
const existingStyles = mergedAttributes[key] ? mergedAttributes[key].split(";").map((style2) => style2.trim()).filter(Boolean) : [];
|
|
1348
|
+
const styleMap = /* @__PURE__ */ new Map();
|
|
1349
|
+
existingStyles.forEach((style2) => {
|
|
1350
|
+
const [property, val] = style2.split(":").map((part) => part.trim());
|
|
1351
|
+
styleMap.set(property, val);
|
|
1352
|
+
});
|
|
1353
|
+
newStyles.forEach((style2) => {
|
|
1354
|
+
const [property, val] = style2.split(":").map((part) => part.trim());
|
|
1355
|
+
styleMap.set(property, val);
|
|
1356
|
+
});
|
|
1357
|
+
mergedAttributes[key] = Array.from(styleMap.entries()).map(([property, val]) => `${property}: ${val}`).join("; ");
|
|
1358
|
+
} else {
|
|
1359
|
+
mergedAttributes[key] = value;
|
|
1360
|
+
}
|
|
1361
|
+
});
|
|
1362
|
+
return mergedAttributes;
|
|
1363
|
+
}, {});
|
|
1364
|
+
}
|
|
1365
|
+
function getRenderedAttributes(nodeOrMark, extensionAttributes) {
|
|
1366
|
+
return extensionAttributes.filter((attribute) => attribute.type === nodeOrMark.type.name).filter((item) => item.attribute.rendered).map((item) => {
|
|
1367
|
+
if (!item.attribute.renderHTML) {
|
|
1368
|
+
return {
|
|
1369
|
+
[item.name]: nodeOrMark.attrs[item.name]
|
|
1370
|
+
};
|
|
1371
|
+
}
|
|
1372
|
+
return item.attribute.renderHTML(nodeOrMark.attrs) || {};
|
|
1373
|
+
}).reduce((attributes, attribute) => mergeAttributes(attributes, attribute), {});
|
|
1374
|
+
}
|
|
1375
|
+
function fromString(value) {
|
|
1376
|
+
if (typeof value !== "string") {
|
|
1377
|
+
return value;
|
|
1378
|
+
}
|
|
1379
|
+
if (value.match(/^[+-]?(?:\d*\.)?\d+$/)) {
|
|
1380
|
+
return Number(value);
|
|
1381
|
+
}
|
|
1382
|
+
if (value === "true") {
|
|
1383
|
+
return true;
|
|
1384
|
+
}
|
|
1385
|
+
if (value === "false") {
|
|
1386
|
+
return false;
|
|
1387
|
+
}
|
|
1388
|
+
return value;
|
|
1389
|
+
}
|
|
1390
|
+
function injectExtensionAttributesToParseRule(parseRule, extensionAttributes) {
|
|
1391
|
+
if ("style" in parseRule) {
|
|
1392
|
+
return parseRule;
|
|
1393
|
+
}
|
|
1394
|
+
return {
|
|
1395
|
+
...parseRule,
|
|
1396
|
+
getAttrs: (node) => {
|
|
1397
|
+
const oldAttributes = parseRule.getAttrs ? parseRule.getAttrs(node) : parseRule.attrs;
|
|
1398
|
+
if (oldAttributes === false) {
|
|
1399
|
+
return false;
|
|
1400
|
+
}
|
|
1401
|
+
const newAttributes = extensionAttributes.reduce((items, item) => {
|
|
1402
|
+
const value = item.attribute.parseHTML ? item.attribute.parseHTML(node) : fromString(node.getAttribute(item.name));
|
|
1403
|
+
if (value === null || value === void 0) {
|
|
1404
|
+
return items;
|
|
1405
|
+
}
|
|
1406
|
+
return {
|
|
1407
|
+
...items,
|
|
1408
|
+
[item.name]: value
|
|
1409
|
+
};
|
|
1410
|
+
}, {});
|
|
1411
|
+
return { ...oldAttributes, ...newAttributes };
|
|
1412
|
+
}
|
|
1413
|
+
};
|
|
1414
|
+
}
|
|
1415
|
+
function cleanUpSchemaItem(data) {
|
|
1416
|
+
return Object.fromEntries(
|
|
1417
|
+
// @ts-ignore
|
|
1418
|
+
Object.entries(data).filter(([key, value]) => {
|
|
1419
|
+
if (key === "attrs" && isEmptyObject(value)) {
|
|
1420
|
+
return false;
|
|
1421
|
+
}
|
|
1422
|
+
return value !== null && value !== void 0;
|
|
1423
|
+
})
|
|
1424
|
+
);
|
|
1425
|
+
}
|
|
1426
|
+
function buildAttributeSpec(extensionAttribute) {
|
|
1427
|
+
var _a, _b;
|
|
1428
|
+
const spec = {};
|
|
1429
|
+
if (!((_a = extensionAttribute == null ? void 0 : extensionAttribute.attribute) == null ? void 0 : _a.isRequired) && "default" in ((extensionAttribute == null ? void 0 : extensionAttribute.attribute) || {})) {
|
|
1430
|
+
spec.default = extensionAttribute.attribute.default;
|
|
1431
|
+
}
|
|
1432
|
+
if (((_b = extensionAttribute == null ? void 0 : extensionAttribute.attribute) == null ? void 0 : _b.validate) !== void 0) {
|
|
1433
|
+
spec.validate = extensionAttribute.attribute.validate;
|
|
1434
|
+
}
|
|
1435
|
+
return [extensionAttribute.name, spec];
|
|
1436
|
+
}
|
|
1437
|
+
function getSchemaByResolvedExtensions(extensions, editor) {
|
|
1438
|
+
var _a;
|
|
1439
|
+
const allAttributes = getAttributesFromExtensions(extensions);
|
|
1440
|
+
const { nodeExtensions, markExtensions } = splitExtensions(extensions);
|
|
1441
|
+
const topNode = (_a = nodeExtensions.find((extension) => getExtensionField(extension, "topNode"))) == null ? void 0 : _a.name;
|
|
1442
|
+
const nodes = Object.fromEntries(
|
|
1443
|
+
nodeExtensions.map((extension) => {
|
|
1444
|
+
const extensionAttributes = allAttributes.filter((attribute) => attribute.type === extension.name);
|
|
1445
|
+
const context = {
|
|
1446
|
+
name: extension.name,
|
|
1447
|
+
options: extension.options,
|
|
1448
|
+
storage: extension.storage,
|
|
1449
|
+
editor
|
|
1450
|
+
};
|
|
1451
|
+
const extraNodeFields = extensions.reduce((fields, e) => {
|
|
1452
|
+
const extendNodeSchema = getExtensionField(e, "extendNodeSchema", context);
|
|
1453
|
+
return {
|
|
1454
|
+
...fields,
|
|
1455
|
+
...extendNodeSchema ? extendNodeSchema(extension) : {}
|
|
1456
|
+
};
|
|
1457
|
+
}, {});
|
|
1458
|
+
const schema = cleanUpSchemaItem({
|
|
1459
|
+
...extraNodeFields,
|
|
1460
|
+
content: callOrReturn(getExtensionField(extension, "content", context)),
|
|
1461
|
+
marks: callOrReturn(getExtensionField(extension, "marks", context)),
|
|
1462
|
+
group: callOrReturn(getExtensionField(extension, "group", context)),
|
|
1463
|
+
inline: callOrReturn(getExtensionField(extension, "inline", context)),
|
|
1464
|
+
atom: callOrReturn(getExtensionField(extension, "atom", context)),
|
|
1465
|
+
selectable: callOrReturn(getExtensionField(extension, "selectable", context)),
|
|
1466
|
+
draggable: callOrReturn(getExtensionField(extension, "draggable", context)),
|
|
1467
|
+
code: callOrReturn(getExtensionField(extension, "code", context)),
|
|
1468
|
+
whitespace: callOrReturn(getExtensionField(extension, "whitespace", context)),
|
|
1469
|
+
linebreakReplacement: callOrReturn(
|
|
1470
|
+
getExtensionField(extension, "linebreakReplacement", context)
|
|
1471
|
+
),
|
|
1472
|
+
defining: callOrReturn(getExtensionField(extension, "defining", context)),
|
|
1473
|
+
isolating: callOrReturn(getExtensionField(extension, "isolating", context)),
|
|
1474
|
+
attrs: Object.fromEntries(extensionAttributes.map(buildAttributeSpec))
|
|
1475
|
+
});
|
|
1476
|
+
const parseHTML = callOrReturn(getExtensionField(extension, "parseHTML", context));
|
|
1477
|
+
if (parseHTML) {
|
|
1478
|
+
schema.parseDOM = parseHTML.map(
|
|
1479
|
+
(parseRule) => injectExtensionAttributesToParseRule(parseRule, extensionAttributes)
|
|
1480
|
+
);
|
|
1481
|
+
}
|
|
1482
|
+
const renderHTML = getExtensionField(extension, "renderHTML", context);
|
|
1483
|
+
if (renderHTML) {
|
|
1484
|
+
schema.toDOM = (node) => renderHTML({
|
|
1485
|
+
node,
|
|
1486
|
+
HTMLAttributes: getRenderedAttributes(node, extensionAttributes)
|
|
1487
|
+
});
|
|
1488
|
+
}
|
|
1489
|
+
const renderText = getExtensionField(extension, "renderText", context);
|
|
1490
|
+
if (renderText) {
|
|
1491
|
+
schema.toText = renderText;
|
|
1492
|
+
}
|
|
1493
|
+
return [extension.name, schema];
|
|
1494
|
+
})
|
|
1495
|
+
);
|
|
1496
|
+
const marks = Object.fromEntries(
|
|
1497
|
+
markExtensions.map((extension) => {
|
|
1498
|
+
const extensionAttributes = allAttributes.filter((attribute) => attribute.type === extension.name);
|
|
1499
|
+
const context = {
|
|
1500
|
+
name: extension.name,
|
|
1501
|
+
options: extension.options,
|
|
1502
|
+
storage: extension.storage,
|
|
1503
|
+
editor
|
|
1504
|
+
};
|
|
1505
|
+
const extraMarkFields = extensions.reduce((fields, e) => {
|
|
1506
|
+
const extendMarkSchema = getExtensionField(e, "extendMarkSchema", context);
|
|
1507
|
+
return {
|
|
1508
|
+
...fields,
|
|
1509
|
+
...extendMarkSchema ? extendMarkSchema(extension) : {}
|
|
1510
|
+
};
|
|
1511
|
+
}, {});
|
|
1512
|
+
const schema = cleanUpSchemaItem({
|
|
1513
|
+
...extraMarkFields,
|
|
1514
|
+
inclusive: callOrReturn(getExtensionField(extension, "inclusive", context)),
|
|
1515
|
+
excludes: callOrReturn(getExtensionField(extension, "excludes", context)),
|
|
1516
|
+
group: callOrReturn(getExtensionField(extension, "group", context)),
|
|
1517
|
+
spanning: callOrReturn(getExtensionField(extension, "spanning", context)),
|
|
1518
|
+
code: callOrReturn(getExtensionField(extension, "code", context)),
|
|
1519
|
+
attrs: Object.fromEntries(extensionAttributes.map(buildAttributeSpec))
|
|
1520
|
+
});
|
|
1521
|
+
const parseHTML = callOrReturn(getExtensionField(extension, "parseHTML", context));
|
|
1522
|
+
if (parseHTML) {
|
|
1523
|
+
schema.parseDOM = parseHTML.map(
|
|
1524
|
+
(parseRule) => injectExtensionAttributesToParseRule(parseRule, extensionAttributes)
|
|
1525
|
+
);
|
|
1526
|
+
}
|
|
1527
|
+
const renderHTML = getExtensionField(extension, "renderHTML", context);
|
|
1528
|
+
if (renderHTML) {
|
|
1529
|
+
schema.toDOM = (mark) => renderHTML({
|
|
1530
|
+
mark,
|
|
1531
|
+
HTMLAttributes: getRenderedAttributes(mark, extensionAttributes)
|
|
1532
|
+
});
|
|
1533
|
+
}
|
|
1534
|
+
return [extension.name, schema];
|
|
1535
|
+
})
|
|
1536
|
+
);
|
|
1537
|
+
return new import_model5.Schema({
|
|
1538
|
+
topNode,
|
|
1539
|
+
nodes,
|
|
1540
|
+
marks
|
|
1541
|
+
});
|
|
1542
|
+
}
|
|
1543
|
+
function findDuplicates(items) {
|
|
1544
|
+
const filtered = items.filter((el, index) => items.indexOf(el) !== index);
|
|
1545
|
+
return Array.from(new Set(filtered));
|
|
1546
|
+
}
|
|
1547
|
+
function sortExtensions(extensions) {
|
|
1548
|
+
const defaultPriority = 100;
|
|
1549
|
+
return extensions.sort((a, b) => {
|
|
1550
|
+
const priorityA = getExtensionField(a, "priority") || defaultPriority;
|
|
1551
|
+
const priorityB = getExtensionField(b, "priority") || defaultPriority;
|
|
1552
|
+
if (priorityA > priorityB) {
|
|
1553
|
+
return -1;
|
|
1554
|
+
}
|
|
1555
|
+
if (priorityA < priorityB) {
|
|
1556
|
+
return 1;
|
|
1557
|
+
}
|
|
1558
|
+
return 0;
|
|
1559
|
+
});
|
|
1560
|
+
}
|
|
1561
|
+
function resolveExtensions(extensions) {
|
|
1562
|
+
const resolvedExtensions = sortExtensions(flattenExtensions(extensions));
|
|
1563
|
+
const duplicatedNames = findDuplicates(resolvedExtensions.map((extension) => extension.name));
|
|
1564
|
+
if (duplicatedNames.length) {
|
|
1565
|
+
console.warn(
|
|
1566
|
+
`[tiptap warn]: Duplicate extension names found: [${duplicatedNames.map((item) => `'${item}'`).join(", ")}]. This can lead to issues.`
|
|
1567
|
+
);
|
|
1568
|
+
}
|
|
1569
|
+
return resolvedExtensions;
|
|
1570
|
+
}
|
|
1571
|
+
function getTextBetween(startNode, range, options) {
|
|
1572
|
+
const { from, to } = range;
|
|
1573
|
+
const { blockSeparator = "\n\n", textSerializers = {} } = options || {};
|
|
1574
|
+
let text = "";
|
|
1575
|
+
startNode.nodesBetween(from, to, (node, pos, parent, index) => {
|
|
1576
|
+
var _a;
|
|
1577
|
+
if (node.isBlock && pos > from) {
|
|
1578
|
+
text += blockSeparator;
|
|
1579
|
+
}
|
|
1580
|
+
const textSerializer = textSerializers == null ? void 0 : textSerializers[node.type.name];
|
|
1581
|
+
if (textSerializer) {
|
|
1582
|
+
if (parent) {
|
|
1583
|
+
text += textSerializer({
|
|
1584
|
+
node,
|
|
1585
|
+
pos,
|
|
1586
|
+
parent,
|
|
1587
|
+
index,
|
|
1588
|
+
range
|
|
1589
|
+
});
|
|
1590
|
+
}
|
|
1591
|
+
return false;
|
|
1592
|
+
}
|
|
1593
|
+
if (node.isText) {
|
|
1594
|
+
text += (_a = node == null ? void 0 : node.text) == null ? void 0 : _a.slice(Math.max(from, pos) - pos, to - pos);
|
|
1595
|
+
}
|
|
1596
|
+
});
|
|
1597
|
+
return text;
|
|
1598
|
+
}
|
|
1599
|
+
function getTextSerializersFromSchema(schema) {
|
|
1600
|
+
return Object.fromEntries(
|
|
1601
|
+
Object.entries(schema.nodes).filter(([, node]) => node.spec.toText).map(([name, node]) => [name, node.spec.toText])
|
|
1602
|
+
);
|
|
1603
|
+
}
|
|
1604
|
+
function removeDuplicates(array, by = JSON.stringify) {
|
|
1605
|
+
const seen = {};
|
|
1606
|
+
return array.filter((item) => {
|
|
1607
|
+
const key = by(item);
|
|
1608
|
+
return Object.prototype.hasOwnProperty.call(seen, key) ? false : seen[key] = true;
|
|
1609
|
+
});
|
|
1610
|
+
}
|
|
1611
|
+
function simplifyChangedRanges(changes) {
|
|
1612
|
+
const uniqueChanges = removeDuplicates(changes);
|
|
1613
|
+
return uniqueChanges.length === 1 ? uniqueChanges : uniqueChanges.filter((change, index) => {
|
|
1614
|
+
const rest = uniqueChanges.filter((_, i) => i !== index);
|
|
1615
|
+
return !rest.some((otherChange) => {
|
|
1616
|
+
return change.oldRange.from >= otherChange.oldRange.from && change.oldRange.to <= otherChange.oldRange.to && change.newRange.from >= otherChange.newRange.from && change.newRange.to <= otherChange.newRange.to;
|
|
1617
|
+
});
|
|
1618
|
+
});
|
|
1619
|
+
}
|
|
1620
|
+
function getChangedRanges(transform) {
|
|
1621
|
+
const { mapping, steps } = transform;
|
|
1622
|
+
const changes = [];
|
|
1623
|
+
mapping.maps.forEach((stepMap, index) => {
|
|
1624
|
+
const ranges = [];
|
|
1625
|
+
if (!stepMap.ranges.length) {
|
|
1626
|
+
const { from, to } = steps[index];
|
|
1627
|
+
if (from === void 0 || to === void 0) {
|
|
1628
|
+
return;
|
|
1629
|
+
}
|
|
1630
|
+
ranges.push({ from, to });
|
|
1631
|
+
} else {
|
|
1632
|
+
stepMap.forEach((from, to) => {
|
|
1633
|
+
ranges.push({ from, to });
|
|
1634
|
+
});
|
|
1635
|
+
}
|
|
1636
|
+
ranges.forEach(({ from, to }) => {
|
|
1637
|
+
const newStart = mapping.slice(index).map(from, -1);
|
|
1638
|
+
const newEnd = mapping.slice(index).map(to);
|
|
1639
|
+
const oldStart = mapping.invert().map(newStart, -1);
|
|
1640
|
+
const oldEnd = mapping.invert().map(newEnd);
|
|
1641
|
+
changes.push({
|
|
1642
|
+
oldRange: {
|
|
1643
|
+
from: oldStart,
|
|
1644
|
+
to: oldEnd
|
|
1645
|
+
},
|
|
1646
|
+
newRange: {
|
|
1647
|
+
from: newStart,
|
|
1648
|
+
to: newEnd
|
|
1649
|
+
}
|
|
1650
|
+
});
|
|
1651
|
+
});
|
|
1652
|
+
});
|
|
1653
|
+
return simplifyChangedRanges(changes);
|
|
1654
|
+
}
|
|
1655
|
+
function getSchemaTypeByName(name, schema) {
|
|
1656
|
+
return schema.nodes[name] || schema.marks[name] || null;
|
|
1657
|
+
}
|
|
1658
|
+
function getSplittedAttributes(extensionAttributes, typeName, attributes) {
|
|
1659
|
+
return Object.fromEntries(
|
|
1660
|
+
Object.entries(attributes).filter(([name]) => {
|
|
1661
|
+
const extensionAttribute = extensionAttributes.find((item) => {
|
|
1662
|
+
return item.type === typeName && item.name === name;
|
|
1663
|
+
});
|
|
1664
|
+
if (!extensionAttribute) {
|
|
1665
|
+
return false;
|
|
1666
|
+
}
|
|
1667
|
+
return extensionAttribute.attribute.keepOnSplit;
|
|
1668
|
+
})
|
|
1669
|
+
);
|
|
1670
|
+
}
|
|
1671
|
+
var getTextContentFromNodes = ($from, maxMatch = 500) => {
|
|
1672
|
+
let textBefore = "";
|
|
1673
|
+
const sliceEndPos = $from.parentOffset;
|
|
1674
|
+
$from.parent.nodesBetween(Math.max(0, sliceEndPos - maxMatch), sliceEndPos, (node, pos, parent, index) => {
|
|
1675
|
+
var _a, _b;
|
|
1676
|
+
const chunk = ((_b = (_a = node.type.spec).toText) == null ? void 0 : _b.call(_a, {
|
|
1677
|
+
node,
|
|
1678
|
+
pos,
|
|
1679
|
+
parent,
|
|
1680
|
+
index
|
|
1681
|
+
})) || node.textContent || "%leaf%";
|
|
1682
|
+
textBefore += node.isAtom && !node.isText ? chunk : chunk.slice(0, Math.max(0, sliceEndPos - pos));
|
|
1683
|
+
});
|
|
1684
|
+
return textBefore;
|
|
1685
|
+
};
|
|
1686
|
+
function isMarkActive(state, typeOrName, attributes = {}) {
|
|
1687
|
+
const { empty, ranges } = state.selection;
|
|
1688
|
+
const type = typeOrName ? getMarkType(typeOrName, state.schema) : null;
|
|
1689
|
+
if (empty) {
|
|
1690
|
+
return !!(state.storedMarks || state.selection.$from.marks()).filter((mark) => {
|
|
1691
|
+
if (!type) {
|
|
1692
|
+
return true;
|
|
1693
|
+
}
|
|
1694
|
+
return type.name === mark.type.name;
|
|
1695
|
+
}).find((mark) => objectIncludes(mark.attrs, attributes, { strict: false }));
|
|
1696
|
+
}
|
|
1697
|
+
let selectionRange = 0;
|
|
1698
|
+
const markRanges = [];
|
|
1699
|
+
ranges.forEach(({ $from, $to }) => {
|
|
1700
|
+
const from = $from.pos;
|
|
1701
|
+
const to = $to.pos;
|
|
1702
|
+
state.doc.nodesBetween(from, to, (node, pos) => {
|
|
1703
|
+
if (!node.isText && !node.marks.length) {
|
|
1704
|
+
return;
|
|
1705
|
+
}
|
|
1706
|
+
const relativeFrom = Math.max(from, pos);
|
|
1707
|
+
const relativeTo = Math.min(to, pos + node.nodeSize);
|
|
1708
|
+
const range2 = relativeTo - relativeFrom;
|
|
1709
|
+
selectionRange += range2;
|
|
1710
|
+
markRanges.push(
|
|
1711
|
+
...node.marks.map((mark) => ({
|
|
1712
|
+
mark,
|
|
1713
|
+
from: relativeFrom,
|
|
1714
|
+
to: relativeTo
|
|
1715
|
+
}))
|
|
1716
|
+
);
|
|
1717
|
+
});
|
|
1718
|
+
});
|
|
1719
|
+
if (selectionRange === 0) {
|
|
1720
|
+
return false;
|
|
1721
|
+
}
|
|
1722
|
+
const matchedRange = markRanges.filter((markRange) => {
|
|
1723
|
+
if (!type) {
|
|
1724
|
+
return true;
|
|
1725
|
+
}
|
|
1726
|
+
return type.name === markRange.mark.type.name;
|
|
1727
|
+
}).filter((markRange) => objectIncludes(markRange.mark.attrs, attributes, { strict: false })).reduce((sum, markRange) => sum + markRange.to - markRange.from, 0);
|
|
1728
|
+
const excludedRange = markRanges.filter((markRange) => {
|
|
1729
|
+
if (!type) {
|
|
1730
|
+
return true;
|
|
1731
|
+
}
|
|
1732
|
+
return markRange.mark.type !== type && markRange.mark.type.excludes(type);
|
|
1733
|
+
}).reduce((sum, markRange) => sum + markRange.to - markRange.from, 0);
|
|
1734
|
+
const range = matchedRange > 0 ? matchedRange + excludedRange : matchedRange;
|
|
1735
|
+
return range >= selectionRange;
|
|
1736
|
+
}
|
|
1737
|
+
function isExtensionRulesEnabled(extension, enabled) {
|
|
1738
|
+
if (Array.isArray(enabled)) {
|
|
1739
|
+
return enabled.some((enabledExtension) => {
|
|
1740
|
+
const name = typeof enabledExtension === "string" ? enabledExtension : enabledExtension.name;
|
|
1741
|
+
return name === extension.name;
|
|
1742
|
+
});
|
|
1743
|
+
}
|
|
1744
|
+
return enabled;
|
|
1745
|
+
}
|
|
1746
|
+
function isList(name, extensions) {
|
|
1747
|
+
const { nodeExtensions } = splitExtensions(extensions);
|
|
1748
|
+
const extension = nodeExtensions.find((item) => item.name === name);
|
|
1749
|
+
if (!extension) {
|
|
1750
|
+
return false;
|
|
1751
|
+
}
|
|
1752
|
+
const context = {
|
|
1753
|
+
name: extension.name,
|
|
1754
|
+
options: extension.options,
|
|
1755
|
+
storage: extension.storage
|
|
1756
|
+
};
|
|
1757
|
+
const group = callOrReturn(getExtensionField(extension, "group", context));
|
|
1758
|
+
if (typeof group !== "string") {
|
|
1759
|
+
return false;
|
|
1760
|
+
}
|
|
1761
|
+
return group.split(" ").includes("list");
|
|
1762
|
+
}
|
|
1763
|
+
function isNodeEmpty(node, {
|
|
1764
|
+
checkChildren = true,
|
|
1765
|
+
ignoreWhitespace = false
|
|
1766
|
+
} = {}) {
|
|
1767
|
+
var _a;
|
|
1768
|
+
if (ignoreWhitespace) {
|
|
1769
|
+
if (node.type.name === "hardBreak") {
|
|
1770
|
+
return true;
|
|
1771
|
+
}
|
|
1772
|
+
if (node.isText) {
|
|
1773
|
+
return /^\s*$/m.test((_a = node.text) != null ? _a : "");
|
|
1774
|
+
}
|
|
1775
|
+
}
|
|
1776
|
+
if (node.isText) {
|
|
1777
|
+
return !node.text;
|
|
1778
|
+
}
|
|
1779
|
+
if (node.isAtom || node.isLeaf) {
|
|
1780
|
+
return false;
|
|
1781
|
+
}
|
|
1782
|
+
if (node.content.childCount === 0) {
|
|
1783
|
+
return true;
|
|
1784
|
+
}
|
|
1785
|
+
if (checkChildren) {
|
|
1786
|
+
let isContentEmpty = true;
|
|
1787
|
+
node.content.forEach((childNode) => {
|
|
1788
|
+
if (isContentEmpty === false) {
|
|
1789
|
+
return;
|
|
1790
|
+
}
|
|
1791
|
+
if (!isNodeEmpty(childNode, { ignoreWhitespace, checkChildren })) {
|
|
1792
|
+
isContentEmpty = false;
|
|
1793
|
+
}
|
|
1794
|
+
});
|
|
1795
|
+
return isContentEmpty;
|
|
1796
|
+
}
|
|
1797
|
+
return false;
|
|
1798
|
+
}
|
|
1799
|
+
function canSetMark(state, tr, newMarkType) {
|
|
1800
|
+
var _a;
|
|
1801
|
+
const { selection } = tr;
|
|
1802
|
+
let cursor = null;
|
|
1803
|
+
if (isTextSelection(selection)) {
|
|
1804
|
+
cursor = selection.$cursor;
|
|
1805
|
+
}
|
|
1806
|
+
if (cursor) {
|
|
1807
|
+
const currentMarks = (_a = state.storedMarks) != null ? _a : cursor.marks();
|
|
1808
|
+
const parentAllowsMarkType = cursor.parent.type.allowsMarkType(newMarkType);
|
|
1809
|
+
return parentAllowsMarkType && (!!newMarkType.isInSet(currentMarks) || !currentMarks.some((mark) => mark.type.excludes(newMarkType)));
|
|
1810
|
+
}
|
|
1811
|
+
const { ranges } = selection;
|
|
1812
|
+
return ranges.some(({ $from, $to }) => {
|
|
1813
|
+
let someNodeSupportsMark = $from.depth === 0 ? state.doc.inlineContent && state.doc.type.allowsMarkType(newMarkType) : false;
|
|
1814
|
+
state.doc.nodesBetween($from.pos, $to.pos, (node, _pos, parent) => {
|
|
1815
|
+
if (someNodeSupportsMark) {
|
|
1816
|
+
return false;
|
|
1817
|
+
}
|
|
1818
|
+
if (node.isInline) {
|
|
1819
|
+
const parentAllowsMarkType = !parent || parent.type.allowsMarkType(newMarkType);
|
|
1820
|
+
const currentMarksAllowMarkType = !!newMarkType.isInSet(node.marks) || !node.marks.some((otherMark) => otherMark.type.excludes(newMarkType));
|
|
1821
|
+
someNodeSupportsMark = parentAllowsMarkType && currentMarksAllowMarkType;
|
|
1822
|
+
}
|
|
1823
|
+
return !someNodeSupportsMark;
|
|
1824
|
+
});
|
|
1825
|
+
return someNodeSupportsMark;
|
|
1826
|
+
});
|
|
1827
|
+
}
|
|
1828
|
+
var setMark = (typeOrName, attributes = {}) => ({ tr, state, dispatch }) => {
|
|
1829
|
+
const { selection } = tr;
|
|
1830
|
+
const { empty, ranges } = selection;
|
|
1831
|
+
const type = getMarkType(typeOrName, state.schema);
|
|
1832
|
+
if (dispatch) {
|
|
1833
|
+
if (empty) {
|
|
1834
|
+
const oldAttributes = getMarkAttributes(state, type);
|
|
1835
|
+
tr.addStoredMark(
|
|
1836
|
+
type.create({
|
|
1837
|
+
...oldAttributes,
|
|
1838
|
+
...attributes
|
|
1839
|
+
})
|
|
1840
|
+
);
|
|
1841
|
+
} else {
|
|
1842
|
+
ranges.forEach((range) => {
|
|
1843
|
+
const from = range.$from.pos;
|
|
1844
|
+
const to = range.$to.pos;
|
|
1845
|
+
state.doc.nodesBetween(from, to, (node, pos) => {
|
|
1846
|
+
const trimmedFrom = Math.max(pos, from);
|
|
1847
|
+
const trimmedTo = Math.min(pos + node.nodeSize, to);
|
|
1848
|
+
const someHasMark = node.marks.find((mark) => mark.type === type);
|
|
1849
|
+
if (someHasMark) {
|
|
1850
|
+
node.marks.forEach((mark) => {
|
|
1851
|
+
if (type === mark.type) {
|
|
1852
|
+
tr.addMark(
|
|
1853
|
+
trimmedFrom,
|
|
1854
|
+
trimmedTo,
|
|
1855
|
+
type.create({
|
|
1856
|
+
...mark.attrs,
|
|
1857
|
+
...attributes
|
|
1858
|
+
})
|
|
1859
|
+
);
|
|
1860
|
+
}
|
|
1861
|
+
});
|
|
1862
|
+
} else {
|
|
1863
|
+
tr.addMark(trimmedFrom, trimmedTo, type.create(attributes));
|
|
1864
|
+
}
|
|
1865
|
+
});
|
|
1866
|
+
});
|
|
1867
|
+
}
|
|
1868
|
+
}
|
|
1869
|
+
return canSetMark(state, tr, type);
|
|
1870
|
+
};
|
|
1871
|
+
var setMeta = (key, value) => ({ tr }) => {
|
|
1872
|
+
tr.setMeta(key, value);
|
|
1873
|
+
return true;
|
|
1874
|
+
};
|
|
1875
|
+
var setNode = (typeOrName, attributes = {}) => ({ state, dispatch, chain }) => {
|
|
1876
|
+
const type = getNodeType(typeOrName, state.schema);
|
|
1877
|
+
let attributesToCopy;
|
|
1878
|
+
if (state.selection.$anchor.sameParent(state.selection.$head)) {
|
|
1879
|
+
attributesToCopy = state.selection.$anchor.parent.attrs;
|
|
1880
|
+
}
|
|
1881
|
+
if (!type.isTextblock) {
|
|
1882
|
+
console.warn('[tiptap warn]: Currently "setNode()" only supports text block nodes.');
|
|
1883
|
+
return false;
|
|
1884
|
+
}
|
|
1885
|
+
return chain().command(({ commands }) => {
|
|
1886
|
+
const canSetBlock = (0, import_commands15.setBlockType)(type, { ...attributesToCopy, ...attributes })(state);
|
|
1887
|
+
if (canSetBlock) {
|
|
1888
|
+
return true;
|
|
1889
|
+
}
|
|
1890
|
+
return commands.clearNodes();
|
|
1891
|
+
}).command(({ state: updatedState }) => {
|
|
1892
|
+
return (0, import_commands15.setBlockType)(type, { ...attributesToCopy, ...attributes })(updatedState, dispatch);
|
|
1893
|
+
}).run();
|
|
1894
|
+
};
|
|
1895
|
+
var setNodeSelection = (position) => ({ tr, dispatch }) => {
|
|
1896
|
+
if (dispatch) {
|
|
1897
|
+
const { doc } = tr;
|
|
1898
|
+
const from = minMax(position, 0, doc.content.size);
|
|
1899
|
+
const selection = import_state8.NodeSelection.create(doc, from);
|
|
1900
|
+
tr.setSelection(selection);
|
|
1901
|
+
}
|
|
1902
|
+
return true;
|
|
1903
|
+
};
|
|
1904
|
+
var setTextDirection = (direction, position) => ({ tr, state, dispatch }) => {
|
|
1905
|
+
const { selection } = state;
|
|
1906
|
+
let from;
|
|
1907
|
+
let to;
|
|
1908
|
+
if (typeof position === "number") {
|
|
1909
|
+
from = position;
|
|
1910
|
+
to = position;
|
|
1911
|
+
} else if (position && "from" in position && "to" in position) {
|
|
1912
|
+
from = position.from;
|
|
1913
|
+
to = position.to;
|
|
1914
|
+
} else {
|
|
1915
|
+
from = selection.from;
|
|
1916
|
+
to = selection.to;
|
|
1917
|
+
}
|
|
1918
|
+
if (dispatch) {
|
|
1919
|
+
tr.doc.nodesBetween(from, to, (node, pos) => {
|
|
1920
|
+
if (node.isText) {
|
|
1921
|
+
return;
|
|
1922
|
+
}
|
|
1923
|
+
tr.setNodeMarkup(pos, void 0, {
|
|
1924
|
+
...node.attrs,
|
|
1925
|
+
dir: direction
|
|
1926
|
+
});
|
|
1927
|
+
});
|
|
1928
|
+
}
|
|
1929
|
+
return true;
|
|
1930
|
+
};
|
|
1931
|
+
var setTextSelection = (position) => ({ tr, dispatch }) => {
|
|
1932
|
+
if (dispatch) {
|
|
1933
|
+
const { doc } = tr;
|
|
1934
|
+
const { from, to } = typeof position === "number" ? { from: position, to: position } : position;
|
|
1935
|
+
const minPos = import_state9.TextSelection.atStart(doc).from;
|
|
1936
|
+
const maxPos = import_state9.TextSelection.atEnd(doc).to;
|
|
1937
|
+
const resolvedFrom = minMax(from, minPos, maxPos);
|
|
1938
|
+
const resolvedEnd = minMax(to, minPos, maxPos);
|
|
1939
|
+
const selection = import_state9.TextSelection.create(doc, resolvedFrom, resolvedEnd);
|
|
1940
|
+
tr.setSelection(selection);
|
|
1941
|
+
}
|
|
1942
|
+
return true;
|
|
1943
|
+
};
|
|
1944
|
+
var sinkListItem = (typeOrName) => ({ state, dispatch }) => {
|
|
1945
|
+
const type = getNodeType(typeOrName, state.schema);
|
|
1946
|
+
return (0, import_schema_list2.sinkListItem)(type)(state, dispatch);
|
|
1947
|
+
};
|
|
1948
|
+
function ensureMarks(state, splittableMarks) {
|
|
1949
|
+
const marks = state.storedMarks || state.selection.$to.parentOffset && state.selection.$from.marks();
|
|
1950
|
+
if (marks) {
|
|
1951
|
+
const filteredMarks = marks.filter((mark) => splittableMarks == null ? void 0 : splittableMarks.includes(mark.type.name));
|
|
1952
|
+
state.tr.ensureMarks(filteredMarks);
|
|
1953
|
+
}
|
|
1954
|
+
}
|
|
1955
|
+
var splitBlock = ({ keepMarks = true } = {}) => ({ tr, state, dispatch, editor }) => {
|
|
1956
|
+
const { selection, doc } = tr;
|
|
1957
|
+
const { $from, $to } = selection;
|
|
1958
|
+
const extensionAttributes = editor.extensionManager.attributes;
|
|
1959
|
+
const newAttributes = getSplittedAttributes(extensionAttributes, $from.node().type.name, $from.node().attrs);
|
|
1960
|
+
if (selection instanceof import_state10.NodeSelection && selection.node.isBlock) {
|
|
1961
|
+
if (!$from.parentOffset || !(0, import_transform6.canSplit)(doc, $from.pos)) {
|
|
1962
|
+
return false;
|
|
1963
|
+
}
|
|
1964
|
+
if (dispatch) {
|
|
1965
|
+
if (keepMarks) {
|
|
1966
|
+
ensureMarks(state, editor.extensionManager.splittableMarks);
|
|
1967
|
+
}
|
|
1968
|
+
tr.split($from.pos).scrollIntoView();
|
|
1969
|
+
}
|
|
1970
|
+
return true;
|
|
1971
|
+
}
|
|
1972
|
+
if (!$from.parent.isBlock) {
|
|
1973
|
+
return false;
|
|
1974
|
+
}
|
|
1975
|
+
const atEnd = $to.parentOffset === $to.parent.content.size;
|
|
1976
|
+
const deflt = $from.depth === 0 ? void 0 : defaultBlockAt($from.node(-1).contentMatchAt($from.indexAfter(-1)));
|
|
1977
|
+
let types = atEnd && deflt ? [
|
|
1978
|
+
{
|
|
1979
|
+
type: deflt,
|
|
1980
|
+
attrs: newAttributes
|
|
1981
|
+
}
|
|
1982
|
+
] : void 0;
|
|
1983
|
+
let can = (0, import_transform6.canSplit)(tr.doc, tr.mapping.map($from.pos), 1, types);
|
|
1984
|
+
if (!types && !can && (0, import_transform6.canSplit)(tr.doc, tr.mapping.map($from.pos), 1, deflt ? [{ type: deflt }] : void 0)) {
|
|
1985
|
+
can = true;
|
|
1986
|
+
types = deflt ? [
|
|
1987
|
+
{
|
|
1988
|
+
type: deflt,
|
|
1989
|
+
attrs: newAttributes
|
|
1990
|
+
}
|
|
1991
|
+
] : void 0;
|
|
1992
|
+
}
|
|
1993
|
+
if (dispatch) {
|
|
1994
|
+
if (can) {
|
|
1995
|
+
if (selection instanceof import_state10.TextSelection) {
|
|
1996
|
+
tr.deleteSelection();
|
|
1997
|
+
}
|
|
1998
|
+
tr.split(tr.mapping.map($from.pos), 1, types);
|
|
1999
|
+
if (deflt && !atEnd && !$from.parentOffset && $from.parent.type !== deflt) {
|
|
2000
|
+
const first2 = tr.mapping.map($from.before());
|
|
2001
|
+
const $first = tr.doc.resolve(first2);
|
|
2002
|
+
if ($from.node(-1).canReplaceWith($first.index(), $first.index() + 1, deflt)) {
|
|
2003
|
+
tr.setNodeMarkup(tr.mapping.map($from.before()), deflt);
|
|
2004
|
+
}
|
|
2005
|
+
}
|
|
2006
|
+
}
|
|
2007
|
+
if (keepMarks) {
|
|
2008
|
+
ensureMarks(state, editor.extensionManager.splittableMarks);
|
|
2009
|
+
}
|
|
2010
|
+
tr.scrollIntoView();
|
|
2011
|
+
}
|
|
2012
|
+
return can;
|
|
2013
|
+
};
|
|
2014
|
+
var splitListItem = (typeOrName, overrideAttrs = {}) => ({ tr, state, dispatch, editor }) => {
|
|
2015
|
+
var _a;
|
|
2016
|
+
const type = getNodeType(typeOrName, state.schema);
|
|
2017
|
+
const { $from, $to } = state.selection;
|
|
2018
|
+
const node = state.selection.node;
|
|
2019
|
+
if (node && node.isBlock || $from.depth < 2 || !$from.sameParent($to)) {
|
|
2020
|
+
return false;
|
|
2021
|
+
}
|
|
2022
|
+
const grandParent = $from.node(-1);
|
|
2023
|
+
if (grandParent.type !== type) {
|
|
2024
|
+
return false;
|
|
2025
|
+
}
|
|
2026
|
+
const extensionAttributes = editor.extensionManager.attributes;
|
|
2027
|
+
if ($from.parent.content.size === 0 && $from.node(-1).childCount === $from.indexAfter(-1)) {
|
|
2028
|
+
if ($from.depth === 2 || $from.node(-3).type !== type || $from.index(-2) !== $from.node(-2).childCount - 1) {
|
|
2029
|
+
return false;
|
|
2030
|
+
}
|
|
2031
|
+
if (dispatch) {
|
|
2032
|
+
let wrap = import_model8.Fragment.empty;
|
|
2033
|
+
const depthBefore = $from.index(-1) ? 1 : $from.index(-2) ? 2 : 3;
|
|
2034
|
+
for (let d = $from.depth - depthBefore; d >= $from.depth - 3; d -= 1) {
|
|
2035
|
+
wrap = import_model8.Fragment.from($from.node(d).copy(wrap));
|
|
2036
|
+
}
|
|
2037
|
+
const depthAfter = (
|
|
2038
|
+
// eslint-disable-next-line no-nested-ternary
|
|
2039
|
+
$from.indexAfter(-1) < $from.node(-2).childCount ? 1 : $from.indexAfter(-2) < $from.node(-3).childCount ? 2 : 3
|
|
2040
|
+
);
|
|
2041
|
+
const newNextTypeAttributes2 = {
|
|
2042
|
+
...getSplittedAttributes(extensionAttributes, $from.node().type.name, $from.node().attrs),
|
|
2043
|
+
...overrideAttrs
|
|
2044
|
+
};
|
|
2045
|
+
const nextType2 = ((_a = type.contentMatch.defaultType) == null ? void 0 : _a.createAndFill(newNextTypeAttributes2)) || void 0;
|
|
2046
|
+
wrap = wrap.append(import_model8.Fragment.from(type.createAndFill(null, nextType2) || void 0));
|
|
2047
|
+
const start = $from.before($from.depth - (depthBefore - 1));
|
|
2048
|
+
tr.replace(start, $from.after(-depthAfter), new import_model8.Slice(wrap, 4 - depthBefore, 0));
|
|
2049
|
+
let sel = -1;
|
|
2050
|
+
tr.doc.nodesBetween(start, tr.doc.content.size, (n, pos) => {
|
|
2051
|
+
if (sel > -1) {
|
|
2052
|
+
return false;
|
|
2053
|
+
}
|
|
2054
|
+
if (n.isTextblock && n.content.size === 0) {
|
|
2055
|
+
sel = pos + 1;
|
|
2056
|
+
}
|
|
2057
|
+
});
|
|
2058
|
+
if (sel > -1) {
|
|
2059
|
+
tr.setSelection(import_state11.TextSelection.near(tr.doc.resolve(sel)));
|
|
2060
|
+
}
|
|
2061
|
+
tr.scrollIntoView();
|
|
2062
|
+
}
|
|
2063
|
+
return true;
|
|
2064
|
+
}
|
|
2065
|
+
const nextType = $to.pos === $from.end() ? grandParent.contentMatchAt(0).defaultType : null;
|
|
2066
|
+
const newTypeAttributes = {
|
|
2067
|
+
...getSplittedAttributes(extensionAttributes, grandParent.type.name, grandParent.attrs),
|
|
2068
|
+
...overrideAttrs
|
|
2069
|
+
};
|
|
2070
|
+
const newNextTypeAttributes = {
|
|
2071
|
+
...getSplittedAttributes(extensionAttributes, $from.node().type.name, $from.node().attrs),
|
|
2072
|
+
...overrideAttrs
|
|
2073
|
+
};
|
|
2074
|
+
tr.delete($from.pos, $to.pos);
|
|
2075
|
+
const types = nextType ? [
|
|
2076
|
+
{ type, attrs: newTypeAttributes },
|
|
2077
|
+
{ type: nextType, attrs: newNextTypeAttributes }
|
|
2078
|
+
] : [{ type, attrs: newTypeAttributes }];
|
|
2079
|
+
if (!(0, import_transform7.canSplit)(tr.doc, $from.pos, 2)) {
|
|
2080
|
+
return false;
|
|
2081
|
+
}
|
|
2082
|
+
if (dispatch) {
|
|
2083
|
+
const { selection, storedMarks } = state;
|
|
2084
|
+
const { splittableMarks } = editor.extensionManager;
|
|
2085
|
+
const marks = storedMarks || selection.$to.parentOffset && selection.$from.marks();
|
|
2086
|
+
tr.split($from.pos, 2, types).scrollIntoView();
|
|
2087
|
+
if (!marks || !dispatch) {
|
|
2088
|
+
return true;
|
|
2089
|
+
}
|
|
2090
|
+
const filteredMarks = marks.filter((mark) => splittableMarks.includes(mark.type.name));
|
|
2091
|
+
tr.ensureMarks(filteredMarks);
|
|
2092
|
+
}
|
|
2093
|
+
return true;
|
|
2094
|
+
};
|
|
2095
|
+
var joinListBackwards = (tr, listType) => {
|
|
2096
|
+
const list = findParentNode((node) => node.type === listType)(tr.selection);
|
|
2097
|
+
if (!list) {
|
|
2098
|
+
return true;
|
|
2099
|
+
}
|
|
2100
|
+
const before = tr.doc.resolve(Math.max(0, list.pos - 1)).before(list.depth);
|
|
2101
|
+
if (before === void 0) {
|
|
2102
|
+
return true;
|
|
2103
|
+
}
|
|
2104
|
+
const nodeBefore = tr.doc.nodeAt(before);
|
|
2105
|
+
const canJoinBackwards = list.node.type === (nodeBefore == null ? void 0 : nodeBefore.type) && (0, import_transform8.canJoin)(tr.doc, list.pos);
|
|
2106
|
+
if (!canJoinBackwards) {
|
|
2107
|
+
return true;
|
|
2108
|
+
}
|
|
2109
|
+
tr.join(list.pos);
|
|
2110
|
+
return true;
|
|
2111
|
+
};
|
|
2112
|
+
var joinListForwards = (tr, listType) => {
|
|
2113
|
+
const list = findParentNode((node) => node.type === listType)(tr.selection);
|
|
2114
|
+
if (!list) {
|
|
2115
|
+
return true;
|
|
2116
|
+
}
|
|
2117
|
+
const after = tr.doc.resolve(list.start).after(list.depth);
|
|
2118
|
+
if (after === void 0) {
|
|
2119
|
+
return true;
|
|
2120
|
+
}
|
|
2121
|
+
const nodeAfter = tr.doc.nodeAt(after);
|
|
2122
|
+
const canJoinForwards = list.node.type === (nodeAfter == null ? void 0 : nodeAfter.type) && (0, import_transform8.canJoin)(tr.doc, after);
|
|
2123
|
+
if (!canJoinForwards) {
|
|
2124
|
+
return true;
|
|
2125
|
+
}
|
|
2126
|
+
tr.join(after);
|
|
2127
|
+
return true;
|
|
2128
|
+
};
|
|
2129
|
+
var toggleList = (listTypeOrName, itemTypeOrName, keepMarks, attributes = {}) => ({ editor, tr, state, dispatch, chain, commands, can }) => {
|
|
2130
|
+
const { extensions, splittableMarks } = editor.extensionManager;
|
|
2131
|
+
const listType = getNodeType(listTypeOrName, state.schema);
|
|
2132
|
+
const itemType = getNodeType(itemTypeOrName, state.schema);
|
|
2133
|
+
const { selection, storedMarks } = state;
|
|
2134
|
+
const { $from, $to } = selection;
|
|
2135
|
+
const range = $from.blockRange($to);
|
|
2136
|
+
const marks = storedMarks || selection.$to.parentOffset && selection.$from.marks();
|
|
2137
|
+
if (!range) {
|
|
2138
|
+
return false;
|
|
2139
|
+
}
|
|
2140
|
+
const parentList = findParentNode((node) => isList(node.type.name, extensions))(selection);
|
|
2141
|
+
if (range.depth >= 1 && parentList && range.depth - parentList.depth <= 1) {
|
|
2142
|
+
if (parentList.node.type === listType) {
|
|
2143
|
+
return commands.liftListItem(itemType);
|
|
2144
|
+
}
|
|
2145
|
+
if (isList(parentList.node.type.name, extensions) && listType.validContent(parentList.node.content) && dispatch) {
|
|
2146
|
+
return chain().command(() => {
|
|
2147
|
+
tr.setNodeMarkup(parentList.pos, listType);
|
|
2148
|
+
return true;
|
|
2149
|
+
}).command(() => joinListBackwards(tr, listType)).command(() => joinListForwards(tr, listType)).run();
|
|
2150
|
+
}
|
|
2151
|
+
}
|
|
2152
|
+
if (!keepMarks || !marks || !dispatch) {
|
|
2153
|
+
return chain().command(() => {
|
|
2154
|
+
const canWrapInList = can().wrapInList(listType, attributes);
|
|
2155
|
+
if (canWrapInList) {
|
|
2156
|
+
return true;
|
|
2157
|
+
}
|
|
2158
|
+
return commands.clearNodes();
|
|
2159
|
+
}).wrapInList(listType, attributes).command(() => joinListBackwards(tr, listType)).command(() => joinListForwards(tr, listType)).run();
|
|
2160
|
+
}
|
|
2161
|
+
return chain().command(() => {
|
|
2162
|
+
const canWrapInList = can().wrapInList(listType, attributes);
|
|
2163
|
+
const filteredMarks = marks.filter((mark) => splittableMarks.includes(mark.type.name));
|
|
2164
|
+
tr.ensureMarks(filteredMarks);
|
|
2165
|
+
if (canWrapInList) {
|
|
2166
|
+
return true;
|
|
2167
|
+
}
|
|
2168
|
+
return commands.clearNodes();
|
|
2169
|
+
}).wrapInList(listType, attributes).command(() => joinListBackwards(tr, listType)).command(() => joinListForwards(tr, listType)).run();
|
|
2170
|
+
};
|
|
2171
|
+
var toggleMark = (typeOrName, attributes = {}, options = {}) => ({ state, commands }) => {
|
|
2172
|
+
const { extendEmptyMarkRange = false } = options;
|
|
2173
|
+
const type = getMarkType(typeOrName, state.schema);
|
|
2174
|
+
const isActive2 = isMarkActive(state, type, attributes);
|
|
2175
|
+
if (isActive2) {
|
|
2176
|
+
return commands.unsetMark(type, { extendEmptyMarkRange });
|
|
2177
|
+
}
|
|
2178
|
+
return commands.setMark(type, attributes);
|
|
2179
|
+
};
|
|
2180
|
+
var toggleNode = (typeOrName, toggleTypeOrName, attributes = {}) => ({ state, commands }) => {
|
|
2181
|
+
const type = getNodeType(typeOrName, state.schema);
|
|
2182
|
+
const toggleType = getNodeType(toggleTypeOrName, state.schema);
|
|
2183
|
+
const isActive2 = isNodeActive(state, type, attributes);
|
|
2184
|
+
let attributesToCopy;
|
|
2185
|
+
if (state.selection.$anchor.sameParent(state.selection.$head)) {
|
|
2186
|
+
attributesToCopy = state.selection.$anchor.parent.attrs;
|
|
2187
|
+
}
|
|
2188
|
+
if (isActive2) {
|
|
2189
|
+
return commands.setNode(toggleType, attributesToCopy);
|
|
2190
|
+
}
|
|
2191
|
+
return commands.setNode(type, { ...attributesToCopy, ...attributes });
|
|
2192
|
+
};
|
|
2193
|
+
var toggleWrap = (typeOrName, attributes = {}) => ({ state, commands }) => {
|
|
2194
|
+
const type = getNodeType(typeOrName, state.schema);
|
|
2195
|
+
const isActive2 = isNodeActive(state, type, attributes);
|
|
2196
|
+
if (isActive2) {
|
|
2197
|
+
return commands.lift(type);
|
|
2198
|
+
}
|
|
2199
|
+
return commands.wrapIn(type, attributes);
|
|
2200
|
+
};
|
|
2201
|
+
var undoInputRule = () => ({ state, dispatch }) => {
|
|
2202
|
+
const plugins = state.plugins;
|
|
2203
|
+
for (let i = 0; i < plugins.length; i += 1) {
|
|
2204
|
+
const plugin = plugins[i];
|
|
2205
|
+
let undoable;
|
|
2206
|
+
if (plugin.spec.isInputRules && (undoable = plugin.getState(state))) {
|
|
2207
|
+
if (dispatch) {
|
|
2208
|
+
const tr = state.tr;
|
|
2209
|
+
const toUndo = undoable.transform;
|
|
2210
|
+
for (let j = toUndo.steps.length - 1; j >= 0; j -= 1) {
|
|
2211
|
+
tr.step(toUndo.steps[j].invert(toUndo.docs[j]));
|
|
2212
|
+
}
|
|
2213
|
+
if (undoable.text) {
|
|
2214
|
+
const marks = tr.doc.resolve(undoable.from).marks();
|
|
2215
|
+
tr.replaceWith(undoable.from, undoable.to, state.schema.text(undoable.text, marks));
|
|
2216
|
+
} else {
|
|
2217
|
+
tr.delete(undoable.from, undoable.to);
|
|
2218
|
+
}
|
|
2219
|
+
}
|
|
2220
|
+
return true;
|
|
2221
|
+
}
|
|
2222
|
+
}
|
|
2223
|
+
return false;
|
|
2224
|
+
};
|
|
2225
|
+
var unsetAllMarks = () => ({ tr, dispatch }) => {
|
|
2226
|
+
const { selection } = tr;
|
|
2227
|
+
const { empty, ranges } = selection;
|
|
2228
|
+
if (empty) {
|
|
2229
|
+
return true;
|
|
2230
|
+
}
|
|
2231
|
+
if (dispatch) {
|
|
2232
|
+
ranges.forEach((range) => {
|
|
2233
|
+
tr.removeMark(range.$from.pos, range.$to.pos);
|
|
2234
|
+
});
|
|
2235
|
+
}
|
|
2236
|
+
return true;
|
|
2237
|
+
};
|
|
2238
|
+
var unsetMark = (typeOrName, options = {}) => ({ tr, state, dispatch }) => {
|
|
2239
|
+
var _a;
|
|
2240
|
+
const { extendEmptyMarkRange = false } = options;
|
|
2241
|
+
const { selection } = tr;
|
|
2242
|
+
const type = getMarkType(typeOrName, state.schema);
|
|
2243
|
+
const { $from, empty, ranges } = selection;
|
|
2244
|
+
if (!dispatch) {
|
|
2245
|
+
return true;
|
|
2246
|
+
}
|
|
2247
|
+
if (empty && extendEmptyMarkRange) {
|
|
2248
|
+
let { from, to } = selection;
|
|
2249
|
+
const attrs = (_a = $from.marks().find((mark) => mark.type === type)) == null ? void 0 : _a.attrs;
|
|
2250
|
+
const range = getMarkRange($from, type, attrs);
|
|
2251
|
+
if (range) {
|
|
2252
|
+
from = range.from;
|
|
2253
|
+
to = range.to;
|
|
2254
|
+
}
|
|
2255
|
+
tr.removeMark(from, to, type);
|
|
2256
|
+
} else {
|
|
2257
|
+
ranges.forEach((range) => {
|
|
2258
|
+
tr.removeMark(range.$from.pos, range.$to.pos, type);
|
|
2259
|
+
});
|
|
2260
|
+
}
|
|
2261
|
+
tr.removeStoredMark(type);
|
|
2262
|
+
return true;
|
|
2263
|
+
};
|
|
2264
|
+
var unsetTextDirection = (position) => ({ tr, state, dispatch }) => {
|
|
2265
|
+
const { selection } = state;
|
|
2266
|
+
let from;
|
|
2267
|
+
let to;
|
|
2268
|
+
if (typeof position === "number") {
|
|
2269
|
+
from = position;
|
|
2270
|
+
to = position;
|
|
2271
|
+
} else if (position && "from" in position && "to" in position) {
|
|
2272
|
+
from = position.from;
|
|
2273
|
+
to = position.to;
|
|
2274
|
+
} else {
|
|
2275
|
+
from = selection.from;
|
|
2276
|
+
to = selection.to;
|
|
2277
|
+
}
|
|
2278
|
+
if (dispatch) {
|
|
2279
|
+
tr.doc.nodesBetween(from, to, (node, pos) => {
|
|
2280
|
+
if (node.isText) {
|
|
2281
|
+
return;
|
|
2282
|
+
}
|
|
2283
|
+
const newAttrs = { ...node.attrs };
|
|
2284
|
+
delete newAttrs.dir;
|
|
2285
|
+
tr.setNodeMarkup(pos, void 0, newAttrs);
|
|
2286
|
+
});
|
|
2287
|
+
}
|
|
2288
|
+
return true;
|
|
2289
|
+
};
|
|
2290
|
+
var updateAttributes = (typeOrName, attributes = {}) => ({ tr, state, dispatch }) => {
|
|
2291
|
+
let nodeType = null;
|
|
2292
|
+
let markType = null;
|
|
2293
|
+
const schemaType = getSchemaTypeNameByName(
|
|
2294
|
+
typeof typeOrName === "string" ? typeOrName : typeOrName.name,
|
|
2295
|
+
state.schema
|
|
2296
|
+
);
|
|
2297
|
+
if (!schemaType) {
|
|
2298
|
+
return false;
|
|
2299
|
+
}
|
|
2300
|
+
if (schemaType === "node") {
|
|
2301
|
+
nodeType = getNodeType(typeOrName, state.schema);
|
|
2302
|
+
}
|
|
2303
|
+
if (schemaType === "mark") {
|
|
2304
|
+
markType = getMarkType(typeOrName, state.schema);
|
|
2305
|
+
}
|
|
2306
|
+
let canUpdate = false;
|
|
2307
|
+
tr.selection.ranges.forEach((range) => {
|
|
2308
|
+
const from = range.$from.pos;
|
|
2309
|
+
const to = range.$to.pos;
|
|
2310
|
+
let lastPos;
|
|
2311
|
+
let lastNode;
|
|
2312
|
+
let trimmedFrom;
|
|
2313
|
+
let trimmedTo;
|
|
2314
|
+
if (tr.selection.empty) {
|
|
2315
|
+
state.doc.nodesBetween(from, to, (node, pos) => {
|
|
2316
|
+
if (nodeType && nodeType === node.type) {
|
|
2317
|
+
canUpdate = true;
|
|
2318
|
+
trimmedFrom = Math.max(pos, from);
|
|
2319
|
+
trimmedTo = Math.min(pos + node.nodeSize, to);
|
|
2320
|
+
lastPos = pos;
|
|
2321
|
+
lastNode = node;
|
|
2322
|
+
}
|
|
2323
|
+
});
|
|
2324
|
+
} else {
|
|
2325
|
+
state.doc.nodesBetween(from, to, (node, pos) => {
|
|
2326
|
+
if (pos < from && nodeType && nodeType === node.type) {
|
|
2327
|
+
canUpdate = true;
|
|
2328
|
+
trimmedFrom = Math.max(pos, from);
|
|
2329
|
+
trimmedTo = Math.min(pos + node.nodeSize, to);
|
|
2330
|
+
lastPos = pos;
|
|
2331
|
+
lastNode = node;
|
|
2332
|
+
}
|
|
2333
|
+
if (pos >= from && pos <= to) {
|
|
2334
|
+
if (nodeType && nodeType === node.type) {
|
|
2335
|
+
canUpdate = true;
|
|
2336
|
+
if (dispatch) {
|
|
2337
|
+
tr.setNodeMarkup(pos, void 0, {
|
|
2338
|
+
...node.attrs,
|
|
2339
|
+
...attributes
|
|
2340
|
+
});
|
|
2341
|
+
}
|
|
2342
|
+
}
|
|
2343
|
+
if (markType && node.marks.length) {
|
|
2344
|
+
node.marks.forEach((mark) => {
|
|
2345
|
+
if (markType === mark.type) {
|
|
2346
|
+
canUpdate = true;
|
|
2347
|
+
if (dispatch) {
|
|
2348
|
+
const trimmedFrom2 = Math.max(pos, from);
|
|
2349
|
+
const trimmedTo2 = Math.min(pos + node.nodeSize, to);
|
|
2350
|
+
tr.addMark(
|
|
2351
|
+
trimmedFrom2,
|
|
2352
|
+
trimmedTo2,
|
|
2353
|
+
markType.create({
|
|
2354
|
+
...mark.attrs,
|
|
2355
|
+
...attributes
|
|
2356
|
+
})
|
|
2357
|
+
);
|
|
2358
|
+
}
|
|
2359
|
+
}
|
|
2360
|
+
});
|
|
2361
|
+
}
|
|
2362
|
+
}
|
|
2363
|
+
});
|
|
2364
|
+
}
|
|
2365
|
+
if (lastNode) {
|
|
2366
|
+
if (lastPos !== void 0 && dispatch) {
|
|
2367
|
+
tr.setNodeMarkup(lastPos, void 0, {
|
|
2368
|
+
...lastNode.attrs,
|
|
2369
|
+
...attributes
|
|
2370
|
+
});
|
|
2371
|
+
}
|
|
2372
|
+
if (markType && lastNode.marks.length) {
|
|
2373
|
+
lastNode.marks.forEach((mark) => {
|
|
2374
|
+
if (markType === mark.type && dispatch) {
|
|
2375
|
+
tr.addMark(
|
|
2376
|
+
trimmedFrom,
|
|
2377
|
+
trimmedTo,
|
|
2378
|
+
markType.create({
|
|
2379
|
+
...mark.attrs,
|
|
2380
|
+
...attributes
|
|
2381
|
+
})
|
|
2382
|
+
);
|
|
2383
|
+
}
|
|
2384
|
+
});
|
|
2385
|
+
}
|
|
2386
|
+
}
|
|
2387
|
+
});
|
|
2388
|
+
return canUpdate;
|
|
2389
|
+
};
|
|
2390
|
+
var wrapIn = (typeOrName, attributes = {}) => ({ state, dispatch }) => {
|
|
2391
|
+
const type = getNodeType(typeOrName, state.schema);
|
|
2392
|
+
return (0, import_commands16.wrapIn)(type, attributes)(state, dispatch);
|
|
2393
|
+
};
|
|
2394
|
+
var wrapInList = (typeOrName, attributes = {}) => ({ state, dispatch }) => {
|
|
2395
|
+
const type = getNodeType(typeOrName, state.schema);
|
|
2396
|
+
return (0, import_schema_list3.wrapInList)(type, attributes)(state, dispatch);
|
|
2397
|
+
};
|
|
2398
|
+
var inputRuleMatcherHandler = (text, find) => {
|
|
2399
|
+
if (isRegExp(find)) {
|
|
2400
|
+
return find.exec(text);
|
|
2401
|
+
}
|
|
2402
|
+
const inputRuleMatch = find(text);
|
|
2403
|
+
if (!inputRuleMatch) {
|
|
2404
|
+
return null;
|
|
2405
|
+
}
|
|
2406
|
+
const result = [inputRuleMatch.text];
|
|
2407
|
+
result.index = inputRuleMatch.index;
|
|
2408
|
+
result.input = text;
|
|
2409
|
+
result.data = inputRuleMatch.data;
|
|
2410
|
+
if (inputRuleMatch.replaceWith) {
|
|
2411
|
+
if (!inputRuleMatch.text.includes(inputRuleMatch.replaceWith)) {
|
|
2412
|
+
console.warn('[tiptap warn]: "inputRuleMatch.replaceWith" must be part of "inputRuleMatch.text".');
|
|
2413
|
+
}
|
|
2414
|
+
result.push(inputRuleMatch.replaceWith);
|
|
2415
|
+
}
|
|
2416
|
+
return result;
|
|
2417
|
+
};
|
|
2418
|
+
function run(config) {
|
|
2419
|
+
var _a;
|
|
2420
|
+
const { editor, from, to, text, rules, plugin } = config;
|
|
2421
|
+
const { view } = editor;
|
|
2422
|
+
if (view.composing) {
|
|
2423
|
+
return false;
|
|
2424
|
+
}
|
|
2425
|
+
const $from = view.state.doc.resolve(from);
|
|
2426
|
+
if (
|
|
2427
|
+
// check for code node
|
|
2428
|
+
$from.parent.type.spec.code || // check for code mark
|
|
2429
|
+
!!((_a = $from.nodeBefore || $from.nodeAfter) == null ? void 0 : _a.marks.find((mark) => mark.type.spec.code))
|
|
2430
|
+
) {
|
|
2431
|
+
return false;
|
|
2432
|
+
}
|
|
2433
|
+
let matched = false;
|
|
2434
|
+
const textBefore = getTextContentFromNodes($from) + text;
|
|
2435
|
+
rules.forEach((rule) => {
|
|
2436
|
+
if (matched) {
|
|
2437
|
+
return;
|
|
2438
|
+
}
|
|
2439
|
+
const match = inputRuleMatcherHandler(textBefore, rule.find);
|
|
2440
|
+
if (!match) {
|
|
2441
|
+
return;
|
|
2442
|
+
}
|
|
2443
|
+
const tr = view.state.tr;
|
|
2444
|
+
const state = createChainableState({
|
|
2445
|
+
state: view.state,
|
|
2446
|
+
transaction: tr
|
|
2447
|
+
});
|
|
2448
|
+
const range = {
|
|
2449
|
+
from: from - (match[0].length - text.length),
|
|
2450
|
+
to
|
|
2451
|
+
};
|
|
2452
|
+
const { commands, chain, can } = new CommandManager({
|
|
2453
|
+
editor,
|
|
2454
|
+
state
|
|
2455
|
+
});
|
|
2456
|
+
const handler = rule.handler({
|
|
2457
|
+
state,
|
|
2458
|
+
range,
|
|
2459
|
+
match,
|
|
2460
|
+
commands,
|
|
2461
|
+
chain,
|
|
2462
|
+
can
|
|
2463
|
+
});
|
|
2464
|
+
if (handler === null || !tr.steps.length) {
|
|
2465
|
+
return;
|
|
2466
|
+
}
|
|
2467
|
+
if (rule.undoable) {
|
|
2468
|
+
tr.setMeta(plugin, {
|
|
2469
|
+
transform: tr,
|
|
2470
|
+
from,
|
|
2471
|
+
to,
|
|
2472
|
+
text
|
|
2473
|
+
});
|
|
2474
|
+
}
|
|
2475
|
+
view.dispatch(tr);
|
|
2476
|
+
matched = true;
|
|
2477
|
+
});
|
|
2478
|
+
return matched;
|
|
2479
|
+
}
|
|
2480
|
+
function inputRulesPlugin(props) {
|
|
2481
|
+
const { editor, rules } = props;
|
|
2482
|
+
const plugin = new import_state13.Plugin({
|
|
2483
|
+
state: {
|
|
2484
|
+
init() {
|
|
2485
|
+
return null;
|
|
2486
|
+
},
|
|
2487
|
+
apply(tr, prev, state) {
|
|
2488
|
+
const stored = tr.getMeta(plugin);
|
|
2489
|
+
if (stored) {
|
|
2490
|
+
return stored;
|
|
2491
|
+
}
|
|
2492
|
+
const simulatedInputMeta = tr.getMeta("applyInputRules");
|
|
2493
|
+
const isSimulatedInput = !!simulatedInputMeta;
|
|
2494
|
+
if (isSimulatedInput) {
|
|
2495
|
+
setTimeout(() => {
|
|
2496
|
+
let { text } = simulatedInputMeta;
|
|
2497
|
+
if (typeof text === "string") {
|
|
2498
|
+
text = text;
|
|
2499
|
+
} else {
|
|
2500
|
+
text = getHTMLFromFragment(import_model9.Fragment.from(text), state.schema);
|
|
2501
|
+
}
|
|
2502
|
+
const { from } = simulatedInputMeta;
|
|
2503
|
+
const to = from + text.length;
|
|
2504
|
+
run({
|
|
2505
|
+
editor,
|
|
2506
|
+
from,
|
|
2507
|
+
to,
|
|
2508
|
+
text,
|
|
2509
|
+
rules,
|
|
2510
|
+
plugin
|
|
2511
|
+
});
|
|
2512
|
+
});
|
|
2513
|
+
}
|
|
2514
|
+
return tr.selectionSet || tr.docChanged ? null : prev;
|
|
2515
|
+
}
|
|
2516
|
+
},
|
|
2517
|
+
props: {
|
|
2518
|
+
handleTextInput(view, from, to, text) {
|
|
2519
|
+
return run({
|
|
2520
|
+
editor,
|
|
2521
|
+
from,
|
|
2522
|
+
to,
|
|
2523
|
+
text,
|
|
2524
|
+
rules,
|
|
2525
|
+
plugin
|
|
2526
|
+
});
|
|
2527
|
+
},
|
|
2528
|
+
handleDOMEvents: {
|
|
2529
|
+
compositionend: (view) => {
|
|
2530
|
+
setTimeout(() => {
|
|
2531
|
+
const { $cursor } = view.state.selection;
|
|
2532
|
+
if ($cursor) {
|
|
2533
|
+
run({
|
|
2534
|
+
editor,
|
|
2535
|
+
from: $cursor.pos,
|
|
2536
|
+
to: $cursor.pos,
|
|
2537
|
+
text: "",
|
|
2538
|
+
rules,
|
|
2539
|
+
plugin
|
|
2540
|
+
});
|
|
2541
|
+
}
|
|
2542
|
+
});
|
|
2543
|
+
return false;
|
|
2544
|
+
}
|
|
2545
|
+
},
|
|
2546
|
+
// add support for input rules to trigger on enter
|
|
2547
|
+
// this is useful for example for code blocks
|
|
2548
|
+
handleKeyDown(view, event) {
|
|
2549
|
+
if (event.key !== "Enter") {
|
|
2550
|
+
return false;
|
|
2551
|
+
}
|
|
2552
|
+
const { $cursor } = view.state.selection;
|
|
2553
|
+
if ($cursor) {
|
|
2554
|
+
return run({
|
|
2555
|
+
editor,
|
|
2556
|
+
from: $cursor.pos,
|
|
2557
|
+
to: $cursor.pos,
|
|
2558
|
+
text: "\n",
|
|
2559
|
+
rules,
|
|
2560
|
+
plugin
|
|
2561
|
+
});
|
|
2562
|
+
}
|
|
2563
|
+
return false;
|
|
2564
|
+
}
|
|
2565
|
+
},
|
|
2566
|
+
// @ts-ignore
|
|
2567
|
+
isInputRules: true
|
|
2568
|
+
});
|
|
2569
|
+
return plugin;
|
|
2570
|
+
}
|
|
2571
|
+
function getType(value) {
|
|
2572
|
+
return Object.prototype.toString.call(value).slice(8, -1);
|
|
2573
|
+
}
|
|
2574
|
+
function isPlainObject(value) {
|
|
2575
|
+
if (getType(value) !== "Object") {
|
|
2576
|
+
return false;
|
|
2577
|
+
}
|
|
2578
|
+
return value.constructor === Object && Object.getPrototypeOf(value) === Object.prototype;
|
|
2579
|
+
}
|
|
2580
|
+
function mergeDeep(target, source) {
|
|
2581
|
+
const output = { ...target };
|
|
2582
|
+
if (isPlainObject(target) && isPlainObject(source)) {
|
|
2583
|
+
Object.keys(source).forEach((key) => {
|
|
2584
|
+
if (isPlainObject(source[key]) && isPlainObject(target[key])) {
|
|
2585
|
+
output[key] = mergeDeep(target[key], source[key]);
|
|
2586
|
+
} else {
|
|
2587
|
+
output[key] = source[key];
|
|
2588
|
+
}
|
|
2589
|
+
});
|
|
2590
|
+
}
|
|
2591
|
+
return output;
|
|
2592
|
+
}
|
|
2593
|
+
var Extendable = class {
|
|
2594
|
+
constructor(config = {}) {
|
|
2595
|
+
this.type = "extendable";
|
|
2596
|
+
this.parent = null;
|
|
2597
|
+
this.child = null;
|
|
2598
|
+
this.name = "";
|
|
2599
|
+
this.config = {
|
|
2600
|
+
name: this.name
|
|
2601
|
+
};
|
|
2602
|
+
this.config = {
|
|
2603
|
+
...this.config,
|
|
2604
|
+
...config
|
|
2605
|
+
};
|
|
2606
|
+
this.name = this.config.name;
|
|
2607
|
+
}
|
|
2608
|
+
get options() {
|
|
2609
|
+
return {
|
|
2610
|
+
...callOrReturn(
|
|
2611
|
+
getExtensionField(this, "addOptions", {
|
|
2612
|
+
name: this.name
|
|
2613
|
+
})
|
|
2614
|
+
) || {}
|
|
2615
|
+
};
|
|
2616
|
+
}
|
|
2617
|
+
get storage() {
|
|
2618
|
+
return {
|
|
2619
|
+
...callOrReturn(
|
|
2620
|
+
getExtensionField(this, "addStorage", {
|
|
2621
|
+
name: this.name,
|
|
2622
|
+
options: this.options
|
|
2623
|
+
})
|
|
2624
|
+
) || {}
|
|
2625
|
+
};
|
|
2626
|
+
}
|
|
2627
|
+
configure(options = {}) {
|
|
2628
|
+
const extension = this.extend({
|
|
2629
|
+
...this.config,
|
|
2630
|
+
addOptions: () => {
|
|
2631
|
+
return mergeDeep(this.options, options);
|
|
2632
|
+
}
|
|
2633
|
+
});
|
|
2634
|
+
extension.name = this.name;
|
|
2635
|
+
extension.parent = this.parent;
|
|
2636
|
+
return extension;
|
|
2637
|
+
}
|
|
2638
|
+
extend(extendedConfig = {}) {
|
|
2639
|
+
const extension = new this.constructor({ ...this.config, ...extendedConfig });
|
|
2640
|
+
extension.parent = this;
|
|
2641
|
+
this.child = extension;
|
|
2642
|
+
extension.name = "name" in extendedConfig ? extendedConfig.name : extension.parent.name;
|
|
2643
|
+
return extension;
|
|
2644
|
+
}
|
|
2645
|
+
};
|
|
2646
|
+
var Mark = class _Mark extends Extendable {
|
|
2647
|
+
constructor() {
|
|
2648
|
+
super(...arguments);
|
|
2649
|
+
this.type = "mark";
|
|
2650
|
+
}
|
|
2651
|
+
/**
|
|
2652
|
+
* Create a new Mark instance
|
|
2653
|
+
* @param config - Mark configuration object or a function that returns a configuration object
|
|
2654
|
+
*/
|
|
2655
|
+
static create(config = {}) {
|
|
2656
|
+
const resolvedConfig = typeof config === "function" ? config() : config;
|
|
2657
|
+
return new _Mark(resolvedConfig);
|
|
2658
|
+
}
|
|
2659
|
+
static handleExit({ editor, mark }) {
|
|
2660
|
+
const { tr } = editor.state;
|
|
2661
|
+
const currentPos = editor.state.selection.$from;
|
|
2662
|
+
const isAtEnd = currentPos.pos === currentPos.end();
|
|
2663
|
+
if (isAtEnd) {
|
|
2664
|
+
const currentMarks = currentPos.marks();
|
|
2665
|
+
const isInMark = !!currentMarks.find((m) => (m == null ? void 0 : m.type.name) === mark.name);
|
|
2666
|
+
if (!isInMark) {
|
|
2667
|
+
return false;
|
|
2668
|
+
}
|
|
2669
|
+
const removeMark = currentMarks.find((m) => (m == null ? void 0 : m.type.name) === mark.name);
|
|
2670
|
+
if (removeMark) {
|
|
2671
|
+
tr.removeStoredMark(removeMark);
|
|
2672
|
+
}
|
|
2673
|
+
tr.insertText(" ", currentPos.pos);
|
|
2674
|
+
editor.view.dispatch(tr);
|
|
2675
|
+
return true;
|
|
2676
|
+
}
|
|
2677
|
+
return false;
|
|
2678
|
+
}
|
|
2679
|
+
configure(options) {
|
|
2680
|
+
return super.configure(options);
|
|
2681
|
+
}
|
|
2682
|
+
extend(extendedConfig) {
|
|
2683
|
+
const resolvedConfig = typeof extendedConfig === "function" ? extendedConfig() : extendedConfig;
|
|
2684
|
+
return super.extend(resolvedConfig);
|
|
2685
|
+
}
|
|
2686
|
+
};
|
|
2687
|
+
function isNumber(value) {
|
|
2688
|
+
return typeof value === "number";
|
|
2689
|
+
}
|
|
2690
|
+
var pasteRuleMatcherHandler = (text, find, event) => {
|
|
2691
|
+
if (isRegExp(find)) {
|
|
2692
|
+
return [...text.matchAll(find)];
|
|
2693
|
+
}
|
|
2694
|
+
const matches = find(text, event);
|
|
2695
|
+
if (!matches) {
|
|
2696
|
+
return [];
|
|
2697
|
+
}
|
|
2698
|
+
return matches.map((pasteRuleMatch) => {
|
|
2699
|
+
const result = [pasteRuleMatch.text];
|
|
2700
|
+
result.index = pasteRuleMatch.index;
|
|
2701
|
+
result.input = text;
|
|
2702
|
+
result.data = pasteRuleMatch.data;
|
|
2703
|
+
if (pasteRuleMatch.replaceWith) {
|
|
2704
|
+
if (!pasteRuleMatch.text.includes(pasteRuleMatch.replaceWith)) {
|
|
2705
|
+
console.warn('[tiptap warn]: "pasteRuleMatch.replaceWith" must be part of "pasteRuleMatch.text".');
|
|
2706
|
+
}
|
|
2707
|
+
result.push(pasteRuleMatch.replaceWith);
|
|
2708
|
+
}
|
|
2709
|
+
return result;
|
|
2710
|
+
});
|
|
2711
|
+
};
|
|
2712
|
+
function run2(config) {
|
|
2713
|
+
const { editor, state, from, to, rule, pasteEvent, dropEvent } = config;
|
|
2714
|
+
const { commands, chain, can } = new CommandManager({
|
|
2715
|
+
editor,
|
|
2716
|
+
state
|
|
2717
|
+
});
|
|
2718
|
+
const handlers = [];
|
|
2719
|
+
state.doc.nodesBetween(from, to, (node, pos) => {
|
|
2720
|
+
var _a, _b, _c, _d, _e;
|
|
2721
|
+
if (((_b = (_a = node.type) == null ? void 0 : _a.spec) == null ? void 0 : _b.code) || !(node.isText || node.isTextblock || node.isInline)) {
|
|
2722
|
+
return;
|
|
2723
|
+
}
|
|
2724
|
+
const contentSize = (_e = (_d = (_c = node.content) == null ? void 0 : _c.size) != null ? _d : node.nodeSize) != null ? _e : 0;
|
|
2725
|
+
const resolvedFrom = Math.max(from, pos);
|
|
2726
|
+
const resolvedTo = Math.min(to, pos + contentSize);
|
|
2727
|
+
if (resolvedFrom >= resolvedTo) {
|
|
2728
|
+
return;
|
|
2729
|
+
}
|
|
2730
|
+
const textToMatch = node.isText ? node.text || "" : node.textBetween(resolvedFrom - pos, resolvedTo - pos, void 0, "\uFFFC");
|
|
2731
|
+
const matches = pasteRuleMatcherHandler(textToMatch, rule.find, pasteEvent);
|
|
2732
|
+
matches.forEach((match) => {
|
|
2733
|
+
if (match.index === void 0) {
|
|
2734
|
+
return;
|
|
2735
|
+
}
|
|
2736
|
+
const start = resolvedFrom + match.index + 1;
|
|
2737
|
+
const end = start + match[0].length;
|
|
2738
|
+
const range = {
|
|
2739
|
+
from: state.tr.mapping.map(start),
|
|
2740
|
+
to: state.tr.mapping.map(end)
|
|
2741
|
+
};
|
|
2742
|
+
const handler = rule.handler({
|
|
2743
|
+
state,
|
|
2744
|
+
range,
|
|
2745
|
+
match,
|
|
2746
|
+
commands,
|
|
2747
|
+
chain,
|
|
2748
|
+
can,
|
|
2749
|
+
pasteEvent,
|
|
2750
|
+
dropEvent
|
|
2751
|
+
});
|
|
2752
|
+
handlers.push(handler);
|
|
2753
|
+
});
|
|
2754
|
+
});
|
|
2755
|
+
const success = handlers.every((handler) => handler !== null);
|
|
2756
|
+
return success;
|
|
2757
|
+
}
|
|
2758
|
+
var tiptapDragFromOtherEditor = null;
|
|
2759
|
+
var createClipboardPasteEvent = (text) => {
|
|
2760
|
+
var _a;
|
|
2761
|
+
const event = new ClipboardEvent("paste", {
|
|
2762
|
+
clipboardData: new DataTransfer()
|
|
2763
|
+
});
|
|
2764
|
+
(_a = event.clipboardData) == null ? void 0 : _a.setData("text/html", text);
|
|
2765
|
+
return event;
|
|
2766
|
+
};
|
|
2767
|
+
function pasteRulesPlugin(props) {
|
|
2768
|
+
const { editor, rules } = props;
|
|
2769
|
+
let dragSourceElement = null;
|
|
2770
|
+
let isPastedFromProseMirror = false;
|
|
2771
|
+
let isDroppedFromProseMirror = false;
|
|
2772
|
+
let pasteEvent = typeof ClipboardEvent !== "undefined" ? new ClipboardEvent("paste") : null;
|
|
2773
|
+
let dropEvent;
|
|
2774
|
+
try {
|
|
2775
|
+
dropEvent = typeof DragEvent !== "undefined" ? new DragEvent("drop") : null;
|
|
2776
|
+
} catch {
|
|
2777
|
+
dropEvent = null;
|
|
2778
|
+
}
|
|
2779
|
+
const processEvent = ({
|
|
2780
|
+
state,
|
|
2781
|
+
from,
|
|
2782
|
+
to,
|
|
2783
|
+
rule,
|
|
2784
|
+
pasteEvt
|
|
2785
|
+
}) => {
|
|
2786
|
+
const tr = state.tr;
|
|
2787
|
+
const chainableState = createChainableState({
|
|
2788
|
+
state,
|
|
2789
|
+
transaction: tr
|
|
2790
|
+
});
|
|
2791
|
+
const handler = run2({
|
|
2792
|
+
editor,
|
|
2793
|
+
state: chainableState,
|
|
2794
|
+
from: Math.max(from - 1, 0),
|
|
2795
|
+
to: to.b - 1,
|
|
2796
|
+
rule,
|
|
2797
|
+
pasteEvent: pasteEvt,
|
|
2798
|
+
dropEvent
|
|
2799
|
+
});
|
|
2800
|
+
if (!handler || !tr.steps.length) {
|
|
2801
|
+
return;
|
|
2802
|
+
}
|
|
2803
|
+
try {
|
|
2804
|
+
dropEvent = typeof DragEvent !== "undefined" ? new DragEvent("drop") : null;
|
|
2805
|
+
} catch {
|
|
2806
|
+
dropEvent = null;
|
|
2807
|
+
}
|
|
2808
|
+
pasteEvent = typeof ClipboardEvent !== "undefined" ? new ClipboardEvent("paste") : null;
|
|
2809
|
+
return tr;
|
|
2810
|
+
};
|
|
2811
|
+
const plugins = rules.map((rule) => {
|
|
2812
|
+
return new import_state14.Plugin({
|
|
2813
|
+
// we register a global drag handler to track the current drag source element
|
|
2814
|
+
view(view) {
|
|
2815
|
+
const handleDragstart = (event) => {
|
|
2816
|
+
var _a;
|
|
2817
|
+
dragSourceElement = ((_a = view.dom.parentElement) == null ? void 0 : _a.contains(event.target)) ? view.dom.parentElement : null;
|
|
2818
|
+
if (dragSourceElement) {
|
|
2819
|
+
tiptapDragFromOtherEditor = editor;
|
|
2820
|
+
}
|
|
2821
|
+
};
|
|
2822
|
+
const handleDragend = () => {
|
|
2823
|
+
if (tiptapDragFromOtherEditor) {
|
|
2824
|
+
tiptapDragFromOtherEditor = null;
|
|
2825
|
+
}
|
|
2826
|
+
};
|
|
2827
|
+
window.addEventListener("dragstart", handleDragstart);
|
|
2828
|
+
window.addEventListener("dragend", handleDragend);
|
|
2829
|
+
return {
|
|
2830
|
+
destroy() {
|
|
2831
|
+
window.removeEventListener("dragstart", handleDragstart);
|
|
2832
|
+
window.removeEventListener("dragend", handleDragend);
|
|
2833
|
+
}
|
|
2834
|
+
};
|
|
2835
|
+
},
|
|
2836
|
+
props: {
|
|
2837
|
+
handleDOMEvents: {
|
|
2838
|
+
drop: (view, event) => {
|
|
2839
|
+
isDroppedFromProseMirror = dragSourceElement === view.dom.parentElement;
|
|
2840
|
+
dropEvent = event;
|
|
2841
|
+
if (!isDroppedFromProseMirror) {
|
|
2842
|
+
const dragFromOtherEditor = tiptapDragFromOtherEditor;
|
|
2843
|
+
if (dragFromOtherEditor == null ? void 0 : dragFromOtherEditor.isEditable) {
|
|
2844
|
+
setTimeout(() => {
|
|
2845
|
+
const selection = dragFromOtherEditor.state.selection;
|
|
2846
|
+
if (selection) {
|
|
2847
|
+
dragFromOtherEditor.commands.deleteRange({ from: selection.from, to: selection.to });
|
|
2848
|
+
}
|
|
2849
|
+
}, 10);
|
|
2850
|
+
}
|
|
2851
|
+
}
|
|
2852
|
+
return false;
|
|
2853
|
+
},
|
|
2854
|
+
paste: (_view, event) => {
|
|
2855
|
+
var _a;
|
|
2856
|
+
const html = (_a = event.clipboardData) == null ? void 0 : _a.getData("text/html");
|
|
2857
|
+
pasteEvent = event;
|
|
2858
|
+
isPastedFromProseMirror = !!(html == null ? void 0 : html.includes("data-pm-slice"));
|
|
2859
|
+
return false;
|
|
2860
|
+
}
|
|
2861
|
+
}
|
|
2862
|
+
},
|
|
2863
|
+
appendTransaction: (transactions, oldState, state) => {
|
|
2864
|
+
const transaction = transactions[0];
|
|
2865
|
+
const isPaste = transaction.getMeta("uiEvent") === "paste" && !isPastedFromProseMirror;
|
|
2866
|
+
const isDrop = transaction.getMeta("uiEvent") === "drop" && !isDroppedFromProseMirror;
|
|
2867
|
+
const simulatedPasteMeta = transaction.getMeta("applyPasteRules");
|
|
2868
|
+
const isSimulatedPaste = !!simulatedPasteMeta;
|
|
2869
|
+
if (!isPaste && !isDrop && !isSimulatedPaste) {
|
|
2870
|
+
return;
|
|
2871
|
+
}
|
|
2872
|
+
if (isSimulatedPaste) {
|
|
2873
|
+
let { text } = simulatedPasteMeta;
|
|
2874
|
+
if (typeof text === "string") {
|
|
2875
|
+
text = text;
|
|
2876
|
+
} else {
|
|
2877
|
+
text = getHTMLFromFragment(import_model10.Fragment.from(text), state.schema);
|
|
2878
|
+
}
|
|
2879
|
+
const { from: from2 } = simulatedPasteMeta;
|
|
2880
|
+
const to2 = from2 + text.length;
|
|
2881
|
+
const pasteEvt = createClipboardPasteEvent(text);
|
|
2882
|
+
return processEvent({
|
|
2883
|
+
rule,
|
|
2884
|
+
state,
|
|
2885
|
+
from: from2,
|
|
2886
|
+
to: { b: to2 },
|
|
2887
|
+
pasteEvt
|
|
2888
|
+
});
|
|
2889
|
+
}
|
|
2890
|
+
const from = oldState.doc.content.findDiffStart(state.doc.content);
|
|
2891
|
+
const to = oldState.doc.content.findDiffEnd(state.doc.content);
|
|
2892
|
+
if (!isNumber(from) || !to || from === to.b) {
|
|
2893
|
+
return;
|
|
2894
|
+
}
|
|
2895
|
+
return processEvent({
|
|
2896
|
+
rule,
|
|
2897
|
+
state,
|
|
2898
|
+
from,
|
|
2899
|
+
to,
|
|
2900
|
+
pasteEvt: pasteEvent
|
|
2901
|
+
});
|
|
2902
|
+
}
|
|
2903
|
+
});
|
|
2904
|
+
});
|
|
2905
|
+
return plugins;
|
|
2906
|
+
}
|
|
2907
|
+
var ExtensionManager = class {
|
|
2908
|
+
constructor(extensions, editor) {
|
|
2909
|
+
this.splittableMarks = [];
|
|
2910
|
+
this.editor = editor;
|
|
2911
|
+
this.baseExtensions = extensions;
|
|
2912
|
+
this.extensions = resolveExtensions(extensions);
|
|
2913
|
+
this.schema = getSchemaByResolvedExtensions(this.extensions, editor);
|
|
2914
|
+
this.setupExtensions();
|
|
2915
|
+
}
|
|
2916
|
+
/**
|
|
2917
|
+
* Get all commands from the extensions.
|
|
2918
|
+
* @returns An object with all commands where the key is the command name and the value is the command function
|
|
2919
|
+
*/
|
|
2920
|
+
get commands() {
|
|
2921
|
+
return this.extensions.reduce((commands, extension) => {
|
|
2922
|
+
const context = {
|
|
2923
|
+
name: extension.name,
|
|
2924
|
+
options: extension.options,
|
|
2925
|
+
storage: this.editor.extensionStorage[extension.name],
|
|
2926
|
+
editor: this.editor,
|
|
2927
|
+
type: getSchemaTypeByName(extension.name, this.schema)
|
|
2928
|
+
};
|
|
2929
|
+
const addCommands = getExtensionField(extension, "addCommands", context);
|
|
2930
|
+
if (!addCommands) {
|
|
2931
|
+
return commands;
|
|
2932
|
+
}
|
|
2933
|
+
return {
|
|
2934
|
+
...commands,
|
|
2935
|
+
...addCommands()
|
|
2936
|
+
};
|
|
2937
|
+
}, {});
|
|
2938
|
+
}
|
|
2939
|
+
/**
|
|
2940
|
+
* Get all registered Prosemirror plugins from the extensions.
|
|
2941
|
+
* @returns An array of Prosemirror plugins
|
|
2942
|
+
*/
|
|
2943
|
+
get plugins() {
|
|
2944
|
+
const { editor } = this;
|
|
2945
|
+
const extensions = sortExtensions([...this.extensions].reverse());
|
|
2946
|
+
const allPlugins = extensions.flatMap((extension) => {
|
|
2947
|
+
const context = {
|
|
2948
|
+
name: extension.name,
|
|
2949
|
+
options: extension.options,
|
|
2950
|
+
storage: this.editor.extensionStorage[extension.name],
|
|
2951
|
+
editor,
|
|
2952
|
+
type: getSchemaTypeByName(extension.name, this.schema)
|
|
2953
|
+
};
|
|
2954
|
+
const plugins = [];
|
|
2955
|
+
const addKeyboardShortcuts = getExtensionField(
|
|
2956
|
+
extension,
|
|
2957
|
+
"addKeyboardShortcuts",
|
|
2958
|
+
context
|
|
2959
|
+
);
|
|
2960
|
+
let defaultBindings = {};
|
|
2961
|
+
if (extension.type === "mark" && getExtensionField(extension, "exitable", context)) {
|
|
2962
|
+
defaultBindings.ArrowRight = () => Mark.handleExit({ editor, mark: extension });
|
|
2963
|
+
}
|
|
2964
|
+
if (addKeyboardShortcuts) {
|
|
2965
|
+
const bindings = Object.fromEntries(
|
|
2966
|
+
Object.entries(addKeyboardShortcuts()).map(([shortcut, method]) => {
|
|
2967
|
+
return [shortcut, () => method({ editor })];
|
|
2968
|
+
})
|
|
2969
|
+
);
|
|
2970
|
+
defaultBindings = { ...defaultBindings, ...bindings };
|
|
2971
|
+
}
|
|
2972
|
+
const keyMapPlugin = (0, import_keymap.keymap)(defaultBindings);
|
|
2973
|
+
plugins.push(keyMapPlugin);
|
|
2974
|
+
const addInputRules = getExtensionField(extension, "addInputRules", context);
|
|
2975
|
+
if (isExtensionRulesEnabled(extension, editor.options.enableInputRules) && addInputRules) {
|
|
2976
|
+
const rules = addInputRules();
|
|
2977
|
+
if (rules && rules.length) {
|
|
2978
|
+
const inputResult = inputRulesPlugin({
|
|
2979
|
+
editor,
|
|
2980
|
+
rules
|
|
2981
|
+
});
|
|
2982
|
+
const inputPlugins = Array.isArray(inputResult) ? inputResult : [inputResult];
|
|
2983
|
+
plugins.push(...inputPlugins);
|
|
2984
|
+
}
|
|
2985
|
+
}
|
|
2986
|
+
const addPasteRules = getExtensionField(extension, "addPasteRules", context);
|
|
2987
|
+
if (isExtensionRulesEnabled(extension, editor.options.enablePasteRules) && addPasteRules) {
|
|
2988
|
+
const rules = addPasteRules();
|
|
2989
|
+
if (rules && rules.length) {
|
|
2990
|
+
const pasteRules = pasteRulesPlugin({ editor, rules });
|
|
2991
|
+
plugins.push(...pasteRules);
|
|
2992
|
+
}
|
|
2993
|
+
}
|
|
2994
|
+
const addProseMirrorPlugins = getExtensionField(
|
|
2995
|
+
extension,
|
|
2996
|
+
"addProseMirrorPlugins",
|
|
2997
|
+
context
|
|
2998
|
+
);
|
|
2999
|
+
if (addProseMirrorPlugins) {
|
|
3000
|
+
const proseMirrorPlugins = addProseMirrorPlugins();
|
|
3001
|
+
plugins.push(...proseMirrorPlugins);
|
|
3002
|
+
}
|
|
3003
|
+
return plugins;
|
|
3004
|
+
});
|
|
3005
|
+
return allPlugins;
|
|
3006
|
+
}
|
|
3007
|
+
/**
|
|
3008
|
+
* Get all attributes from the extensions.
|
|
3009
|
+
* @returns An array of attributes
|
|
3010
|
+
*/
|
|
3011
|
+
get attributes() {
|
|
3012
|
+
return getAttributesFromExtensions(this.extensions);
|
|
3013
|
+
}
|
|
3014
|
+
/**
|
|
3015
|
+
* Get all node views from the extensions.
|
|
3016
|
+
* @returns An object with all node views where the key is the node name and the value is the node view function
|
|
3017
|
+
*/
|
|
3018
|
+
get nodeViews() {
|
|
3019
|
+
const { editor } = this;
|
|
3020
|
+
const { nodeExtensions } = splitExtensions(this.extensions);
|
|
3021
|
+
return Object.fromEntries(
|
|
3022
|
+
nodeExtensions.filter((extension) => !!getExtensionField(extension, "addNodeView")).map((extension) => {
|
|
3023
|
+
const extensionAttributes = this.attributes.filter((attribute) => attribute.type === extension.name);
|
|
3024
|
+
const context = {
|
|
3025
|
+
name: extension.name,
|
|
3026
|
+
options: extension.options,
|
|
3027
|
+
storage: this.editor.extensionStorage[extension.name],
|
|
3028
|
+
editor,
|
|
3029
|
+
type: getNodeType(extension.name, this.schema)
|
|
3030
|
+
};
|
|
3031
|
+
const addNodeView = getExtensionField(extension, "addNodeView", context);
|
|
3032
|
+
if (!addNodeView) {
|
|
3033
|
+
return [];
|
|
3034
|
+
}
|
|
3035
|
+
const nodeViewResult = addNodeView();
|
|
3036
|
+
if (!nodeViewResult) {
|
|
3037
|
+
return [];
|
|
3038
|
+
}
|
|
3039
|
+
const nodeview = (node, view, getPos, decorations, innerDecorations) => {
|
|
3040
|
+
const HTMLAttributes = getRenderedAttributes(node, extensionAttributes);
|
|
3041
|
+
return nodeViewResult({
|
|
3042
|
+
// pass-through
|
|
3043
|
+
node,
|
|
3044
|
+
view,
|
|
3045
|
+
getPos,
|
|
3046
|
+
decorations,
|
|
3047
|
+
innerDecorations,
|
|
3048
|
+
// tiptap-specific
|
|
3049
|
+
editor,
|
|
3050
|
+
extension,
|
|
3051
|
+
HTMLAttributes
|
|
3052
|
+
});
|
|
3053
|
+
};
|
|
3054
|
+
return [extension.name, nodeview];
|
|
3055
|
+
})
|
|
3056
|
+
);
|
|
3057
|
+
}
|
|
3058
|
+
/**
|
|
3059
|
+
* Get the composed dispatchTransaction function from all extensions.
|
|
3060
|
+
* @param baseDispatch The base dispatch function (e.g. from the editor or user props)
|
|
3061
|
+
* @returns A composed dispatch function
|
|
3062
|
+
*/
|
|
3063
|
+
dispatchTransaction(baseDispatch) {
|
|
3064
|
+
const { editor } = this;
|
|
3065
|
+
const extensions = sortExtensions([...this.extensions].reverse());
|
|
3066
|
+
return extensions.reduceRight((next, extension) => {
|
|
3067
|
+
const context = {
|
|
3068
|
+
name: extension.name,
|
|
3069
|
+
options: extension.options,
|
|
3070
|
+
storage: this.editor.extensionStorage[extension.name],
|
|
3071
|
+
editor,
|
|
3072
|
+
type: getSchemaTypeByName(extension.name, this.schema)
|
|
3073
|
+
};
|
|
3074
|
+
const dispatchTransaction = getExtensionField(
|
|
3075
|
+
extension,
|
|
3076
|
+
"dispatchTransaction",
|
|
3077
|
+
context
|
|
3078
|
+
);
|
|
3079
|
+
if (!dispatchTransaction) {
|
|
3080
|
+
return next;
|
|
3081
|
+
}
|
|
3082
|
+
return (transaction) => {
|
|
3083
|
+
dispatchTransaction.call(context, { transaction, next });
|
|
3084
|
+
};
|
|
3085
|
+
}, baseDispatch);
|
|
3086
|
+
}
|
|
3087
|
+
get markViews() {
|
|
3088
|
+
const { editor } = this;
|
|
3089
|
+
const { markExtensions } = splitExtensions(this.extensions);
|
|
3090
|
+
return Object.fromEntries(
|
|
3091
|
+
markExtensions.filter((extension) => !!getExtensionField(extension, "addMarkView")).map((extension) => {
|
|
3092
|
+
const extensionAttributes = this.attributes.filter((attribute) => attribute.type === extension.name);
|
|
3093
|
+
const context = {
|
|
3094
|
+
name: extension.name,
|
|
3095
|
+
options: extension.options,
|
|
3096
|
+
storage: this.editor.extensionStorage[extension.name],
|
|
3097
|
+
editor,
|
|
3098
|
+
type: getMarkType(extension.name, this.schema)
|
|
3099
|
+
};
|
|
3100
|
+
const addMarkView = getExtensionField(extension, "addMarkView", context);
|
|
3101
|
+
if (!addMarkView) {
|
|
3102
|
+
return [];
|
|
3103
|
+
}
|
|
3104
|
+
const markView = (mark, view, inline) => {
|
|
3105
|
+
const HTMLAttributes = getRenderedAttributes(mark, extensionAttributes);
|
|
3106
|
+
return addMarkView()({
|
|
3107
|
+
// pass-through
|
|
3108
|
+
mark,
|
|
3109
|
+
view,
|
|
3110
|
+
inline,
|
|
3111
|
+
// tiptap-specific
|
|
3112
|
+
editor,
|
|
3113
|
+
extension,
|
|
3114
|
+
HTMLAttributes,
|
|
3115
|
+
updateAttributes: (attrs) => {
|
|
3116
|
+
updateMarkViewAttributes(mark, editor, attrs);
|
|
3117
|
+
}
|
|
3118
|
+
});
|
|
3119
|
+
};
|
|
3120
|
+
return [extension.name, markView];
|
|
3121
|
+
})
|
|
3122
|
+
);
|
|
3123
|
+
}
|
|
3124
|
+
/**
|
|
3125
|
+
* Go through all extensions, create extension storages & setup marks
|
|
3126
|
+
* & bind editor event listener.
|
|
3127
|
+
*/
|
|
3128
|
+
setupExtensions() {
|
|
3129
|
+
const extensions = this.extensions;
|
|
3130
|
+
this.editor.extensionStorage = Object.fromEntries(
|
|
3131
|
+
extensions.map((extension) => [extension.name, extension.storage])
|
|
3132
|
+
);
|
|
3133
|
+
extensions.forEach((extension) => {
|
|
3134
|
+
var _a;
|
|
3135
|
+
const context = {
|
|
3136
|
+
name: extension.name,
|
|
3137
|
+
options: extension.options,
|
|
3138
|
+
storage: this.editor.extensionStorage[extension.name],
|
|
3139
|
+
editor: this.editor,
|
|
3140
|
+
type: getSchemaTypeByName(extension.name, this.schema)
|
|
3141
|
+
};
|
|
3142
|
+
if (extension.type === "mark") {
|
|
3143
|
+
const keepOnSplit = (_a = callOrReturn(getExtensionField(extension, "keepOnSplit", context))) != null ? _a : true;
|
|
3144
|
+
if (keepOnSplit) {
|
|
3145
|
+
this.splittableMarks.push(extension.name);
|
|
3146
|
+
}
|
|
3147
|
+
}
|
|
3148
|
+
const onBeforeCreate = getExtensionField(extension, "onBeforeCreate", context);
|
|
3149
|
+
const onCreate = getExtensionField(extension, "onCreate", context);
|
|
3150
|
+
const onUpdate = getExtensionField(extension, "onUpdate", context);
|
|
3151
|
+
const onSelectionUpdate = getExtensionField(
|
|
3152
|
+
extension,
|
|
3153
|
+
"onSelectionUpdate",
|
|
3154
|
+
context
|
|
3155
|
+
);
|
|
3156
|
+
const onTransaction = getExtensionField(extension, "onTransaction", context);
|
|
3157
|
+
const onFocus = getExtensionField(extension, "onFocus", context);
|
|
3158
|
+
const onBlur = getExtensionField(extension, "onBlur", context);
|
|
3159
|
+
const onDestroy = getExtensionField(extension, "onDestroy", context);
|
|
3160
|
+
if (onBeforeCreate) {
|
|
3161
|
+
this.editor.on("beforeCreate", onBeforeCreate);
|
|
3162
|
+
}
|
|
3163
|
+
if (onCreate) {
|
|
3164
|
+
this.editor.on("create", onCreate);
|
|
3165
|
+
}
|
|
3166
|
+
if (onUpdate) {
|
|
3167
|
+
this.editor.on("update", onUpdate);
|
|
3168
|
+
}
|
|
3169
|
+
if (onSelectionUpdate) {
|
|
3170
|
+
this.editor.on("selectionUpdate", onSelectionUpdate);
|
|
3171
|
+
}
|
|
3172
|
+
if (onTransaction) {
|
|
3173
|
+
this.editor.on("transaction", onTransaction);
|
|
3174
|
+
}
|
|
3175
|
+
if (onFocus) {
|
|
3176
|
+
this.editor.on("focus", onFocus);
|
|
3177
|
+
}
|
|
3178
|
+
if (onBlur) {
|
|
3179
|
+
this.editor.on("blur", onBlur);
|
|
3180
|
+
}
|
|
3181
|
+
if (onDestroy) {
|
|
3182
|
+
this.editor.on("destroy", onDestroy);
|
|
3183
|
+
}
|
|
3184
|
+
});
|
|
3185
|
+
}
|
|
3186
|
+
};
|
|
3187
|
+
ExtensionManager.resolve = resolveExtensions;
|
|
3188
|
+
ExtensionManager.sort = sortExtensions;
|
|
3189
|
+
ExtensionManager.flatten = flattenExtensions;
|
|
3190
|
+
var extensions_exports = {};
|
|
3191
|
+
__export2(extensions_exports, {
|
|
3192
|
+
ClipboardTextSerializer: () => ClipboardTextSerializer,
|
|
3193
|
+
Commands: () => Commands,
|
|
3194
|
+
Delete: () => Delete,
|
|
3195
|
+
Drop: () => Drop,
|
|
3196
|
+
Editable: () => Editable,
|
|
3197
|
+
FocusEvents: () => FocusEvents,
|
|
3198
|
+
Keymap: () => Keymap,
|
|
3199
|
+
Paste: () => Paste,
|
|
3200
|
+
Tabindex: () => Tabindex,
|
|
3201
|
+
TextDirection: () => TextDirection,
|
|
3202
|
+
focusEventsPluginKey: () => focusEventsPluginKey
|
|
3203
|
+
});
|
|
3204
|
+
var Extension = class _Extension extends Extendable {
|
|
3205
|
+
constructor() {
|
|
3206
|
+
super(...arguments);
|
|
3207
|
+
this.type = "extension";
|
|
3208
|
+
}
|
|
3209
|
+
/**
|
|
3210
|
+
* Create a new Extension instance
|
|
3211
|
+
* @param config - Extension configuration object or a function that returns a configuration object
|
|
3212
|
+
*/
|
|
3213
|
+
static create(config = {}) {
|
|
3214
|
+
const resolvedConfig = typeof config === "function" ? config() : config;
|
|
3215
|
+
return new _Extension(resolvedConfig);
|
|
3216
|
+
}
|
|
3217
|
+
configure(options) {
|
|
3218
|
+
return super.configure(options);
|
|
3219
|
+
}
|
|
3220
|
+
extend(extendedConfig) {
|
|
3221
|
+
const resolvedConfig = typeof extendedConfig === "function" ? extendedConfig() : extendedConfig;
|
|
3222
|
+
return super.extend(resolvedConfig);
|
|
3223
|
+
}
|
|
3224
|
+
};
|
|
3225
|
+
var ClipboardTextSerializer = Extension.create({
|
|
3226
|
+
name: "clipboardTextSerializer",
|
|
3227
|
+
addOptions() {
|
|
3228
|
+
return {
|
|
3229
|
+
blockSeparator: void 0
|
|
3230
|
+
};
|
|
3231
|
+
},
|
|
3232
|
+
addProseMirrorPlugins() {
|
|
3233
|
+
return [
|
|
3234
|
+
new import_state15.Plugin({
|
|
3235
|
+
key: new import_state15.PluginKey("clipboardTextSerializer"),
|
|
3236
|
+
props: {
|
|
3237
|
+
clipboardTextSerializer: () => {
|
|
3238
|
+
const { editor } = this;
|
|
3239
|
+
const { state, schema } = editor;
|
|
3240
|
+
const { doc, selection } = state;
|
|
3241
|
+
const { ranges } = selection;
|
|
3242
|
+
const from = Math.min(...ranges.map((range2) => range2.$from.pos));
|
|
3243
|
+
const to = Math.max(...ranges.map((range2) => range2.$to.pos));
|
|
3244
|
+
const textSerializers = getTextSerializersFromSchema(schema);
|
|
3245
|
+
const range = { from, to };
|
|
3246
|
+
return getTextBetween(doc, range, {
|
|
3247
|
+
...this.options.blockSeparator !== void 0 ? { blockSeparator: this.options.blockSeparator } : {},
|
|
3248
|
+
textSerializers
|
|
3249
|
+
});
|
|
3250
|
+
}
|
|
3251
|
+
}
|
|
3252
|
+
})
|
|
3253
|
+
];
|
|
3254
|
+
}
|
|
3255
|
+
});
|
|
3256
|
+
var Commands = Extension.create({
|
|
3257
|
+
name: "commands",
|
|
3258
|
+
addCommands() {
|
|
3259
|
+
return {
|
|
3260
|
+
...commands_exports
|
|
3261
|
+
};
|
|
3262
|
+
}
|
|
3263
|
+
});
|
|
3264
|
+
var Delete = Extension.create({
|
|
3265
|
+
name: "delete",
|
|
3266
|
+
onUpdate({ transaction, appendedTransactions }) {
|
|
3267
|
+
var _a, _b, _c;
|
|
3268
|
+
const callback = () => {
|
|
3269
|
+
var _a2, _b2, _c2, _d;
|
|
3270
|
+
if ((_d = (_c2 = (_b2 = (_a2 = this.editor.options.coreExtensionOptions) == null ? void 0 : _a2.delete) == null ? void 0 : _b2.filterTransaction) == null ? void 0 : _c2.call(_b2, transaction)) != null ? _d : transaction.getMeta("y-sync$")) {
|
|
3271
|
+
return;
|
|
3272
|
+
}
|
|
3273
|
+
const nextTransaction = combineTransactionSteps(transaction.before, [transaction, ...appendedTransactions]);
|
|
3274
|
+
const changes = getChangedRanges(nextTransaction);
|
|
3275
|
+
changes.forEach((change) => {
|
|
3276
|
+
if (nextTransaction.mapping.mapResult(change.oldRange.from).deletedAfter && nextTransaction.mapping.mapResult(change.oldRange.to).deletedBefore) {
|
|
3277
|
+
nextTransaction.before.nodesBetween(change.oldRange.from, change.oldRange.to, (node, from) => {
|
|
3278
|
+
const to = from + node.nodeSize - 2;
|
|
3279
|
+
const isFullyWithinRange = change.oldRange.from <= from && to <= change.oldRange.to;
|
|
3280
|
+
this.editor.emit("delete", {
|
|
3281
|
+
type: "node",
|
|
3282
|
+
node,
|
|
3283
|
+
from,
|
|
3284
|
+
to,
|
|
3285
|
+
newFrom: nextTransaction.mapping.map(from),
|
|
3286
|
+
newTo: nextTransaction.mapping.map(to),
|
|
3287
|
+
deletedRange: change.oldRange,
|
|
3288
|
+
newRange: change.newRange,
|
|
3289
|
+
partial: !isFullyWithinRange,
|
|
3290
|
+
editor: this.editor,
|
|
3291
|
+
transaction,
|
|
3292
|
+
combinedTransform: nextTransaction
|
|
3293
|
+
});
|
|
3294
|
+
});
|
|
3295
|
+
}
|
|
3296
|
+
});
|
|
3297
|
+
const mapping = nextTransaction.mapping;
|
|
3298
|
+
nextTransaction.steps.forEach((step, index) => {
|
|
3299
|
+
var _a3, _b3;
|
|
3300
|
+
if (step instanceof import_transform9.RemoveMarkStep) {
|
|
3301
|
+
const newStart = mapping.slice(index).map(step.from, -1);
|
|
3302
|
+
const newEnd = mapping.slice(index).map(step.to);
|
|
3303
|
+
const oldStart = mapping.invert().map(newStart, -1);
|
|
3304
|
+
const oldEnd = mapping.invert().map(newEnd);
|
|
3305
|
+
const foundBeforeMark = (_a3 = nextTransaction.doc.nodeAt(newStart - 1)) == null ? void 0 : _a3.marks.some((mark) => mark.eq(step.mark));
|
|
3306
|
+
const foundAfterMark = (_b3 = nextTransaction.doc.nodeAt(newEnd)) == null ? void 0 : _b3.marks.some((mark) => mark.eq(step.mark));
|
|
3307
|
+
this.editor.emit("delete", {
|
|
3308
|
+
type: "mark",
|
|
3309
|
+
mark: step.mark,
|
|
3310
|
+
from: step.from,
|
|
3311
|
+
to: step.to,
|
|
3312
|
+
deletedRange: {
|
|
3313
|
+
from: oldStart,
|
|
3314
|
+
to: oldEnd
|
|
3315
|
+
},
|
|
3316
|
+
newRange: {
|
|
3317
|
+
from: newStart,
|
|
3318
|
+
to: newEnd
|
|
3319
|
+
},
|
|
3320
|
+
partial: Boolean(foundAfterMark || foundBeforeMark),
|
|
3321
|
+
editor: this.editor,
|
|
3322
|
+
transaction,
|
|
3323
|
+
combinedTransform: nextTransaction
|
|
3324
|
+
});
|
|
3325
|
+
}
|
|
3326
|
+
});
|
|
3327
|
+
};
|
|
3328
|
+
if ((_c = (_b = (_a = this.editor.options.coreExtensionOptions) == null ? void 0 : _a.delete) == null ? void 0 : _b.async) != null ? _c : true) {
|
|
3329
|
+
setTimeout(callback, 0);
|
|
3330
|
+
} else {
|
|
3331
|
+
callback();
|
|
3332
|
+
}
|
|
3333
|
+
}
|
|
3334
|
+
});
|
|
3335
|
+
var Drop = Extension.create({
|
|
3336
|
+
name: "drop",
|
|
3337
|
+
addProseMirrorPlugins() {
|
|
3338
|
+
return [
|
|
3339
|
+
new import_state16.Plugin({
|
|
3340
|
+
key: new import_state16.PluginKey("tiptapDrop"),
|
|
3341
|
+
props: {
|
|
3342
|
+
handleDrop: (_, e, slice, moved) => {
|
|
3343
|
+
this.editor.emit("drop", {
|
|
3344
|
+
editor: this.editor,
|
|
3345
|
+
event: e,
|
|
3346
|
+
slice,
|
|
3347
|
+
moved
|
|
3348
|
+
});
|
|
3349
|
+
}
|
|
3350
|
+
}
|
|
3351
|
+
})
|
|
3352
|
+
];
|
|
3353
|
+
}
|
|
3354
|
+
});
|
|
3355
|
+
var Editable = Extension.create({
|
|
3356
|
+
name: "editable",
|
|
3357
|
+
addProseMirrorPlugins() {
|
|
3358
|
+
return [
|
|
3359
|
+
new import_state17.Plugin({
|
|
3360
|
+
key: new import_state17.PluginKey("editable"),
|
|
3361
|
+
props: {
|
|
3362
|
+
editable: () => this.editor.options.editable
|
|
3363
|
+
}
|
|
3364
|
+
})
|
|
3365
|
+
];
|
|
3366
|
+
}
|
|
3367
|
+
});
|
|
3368
|
+
var focusEventsPluginKey = new import_state18.PluginKey("focusEvents");
|
|
3369
|
+
var FocusEvents = Extension.create({
|
|
3370
|
+
name: "focusEvents",
|
|
3371
|
+
addProseMirrorPlugins() {
|
|
3372
|
+
const { editor } = this;
|
|
3373
|
+
return [
|
|
3374
|
+
new import_state18.Plugin({
|
|
3375
|
+
key: focusEventsPluginKey,
|
|
3376
|
+
props: {
|
|
3377
|
+
handleDOMEvents: {
|
|
3378
|
+
focus: (view, event) => {
|
|
3379
|
+
editor.isFocused = true;
|
|
3380
|
+
const transaction = editor.state.tr.setMeta("focus", { event }).setMeta("addToHistory", false);
|
|
3381
|
+
view.dispatch(transaction);
|
|
3382
|
+
return false;
|
|
3383
|
+
},
|
|
3384
|
+
blur: (view, event) => {
|
|
3385
|
+
editor.isFocused = false;
|
|
3386
|
+
const transaction = editor.state.tr.setMeta("blur", { event }).setMeta("addToHistory", false);
|
|
3387
|
+
view.dispatch(transaction);
|
|
3388
|
+
return false;
|
|
3389
|
+
}
|
|
3390
|
+
}
|
|
3391
|
+
}
|
|
3392
|
+
})
|
|
3393
|
+
];
|
|
3394
|
+
}
|
|
3395
|
+
});
|
|
3396
|
+
var Keymap = Extension.create({
|
|
3397
|
+
name: "keymap",
|
|
3398
|
+
addKeyboardShortcuts() {
|
|
3399
|
+
const handleBackspace = () => this.editor.commands.first(({ commands }) => [
|
|
3400
|
+
() => commands.undoInputRule(),
|
|
3401
|
+
// maybe convert first text block node to default node
|
|
3402
|
+
() => commands.command(({ tr }) => {
|
|
3403
|
+
const { selection, doc } = tr;
|
|
3404
|
+
const { empty, $anchor } = selection;
|
|
3405
|
+
const { pos, parent } = $anchor;
|
|
3406
|
+
const $parentPos = $anchor.parent.isTextblock && pos > 0 ? tr.doc.resolve(pos - 1) : $anchor;
|
|
3407
|
+
const parentIsIsolating = $parentPos.parent.type.spec.isolating;
|
|
3408
|
+
const parentPos = $anchor.pos - $anchor.parentOffset;
|
|
3409
|
+
const isAtStart = parentIsIsolating && $parentPos.parent.childCount === 1 ? parentPos === $anchor.pos : import_state19.Selection.atStart(doc).from === pos;
|
|
3410
|
+
if (!empty || !parent.type.isTextblock || parent.textContent.length || !isAtStart || isAtStart && $anchor.parent.type.name === "paragraph") {
|
|
3411
|
+
return false;
|
|
3412
|
+
}
|
|
3413
|
+
return commands.clearNodes();
|
|
3414
|
+
}),
|
|
3415
|
+
() => commands.deleteSelection(),
|
|
3416
|
+
() => commands.joinBackward(),
|
|
3417
|
+
() => commands.selectNodeBackward()
|
|
3418
|
+
]);
|
|
3419
|
+
const handleDelete = () => this.editor.commands.first(({ commands }) => [
|
|
3420
|
+
() => commands.deleteSelection(),
|
|
3421
|
+
() => commands.deleteCurrentNode(),
|
|
3422
|
+
() => commands.joinForward(),
|
|
3423
|
+
() => commands.selectNodeForward()
|
|
3424
|
+
]);
|
|
3425
|
+
const handleEnter = () => this.editor.commands.first(({ commands }) => [
|
|
3426
|
+
() => commands.newlineInCode(),
|
|
3427
|
+
() => commands.createParagraphNear(),
|
|
3428
|
+
() => commands.liftEmptyBlock(),
|
|
3429
|
+
() => commands.splitBlock()
|
|
3430
|
+
]);
|
|
3431
|
+
const baseKeymap = {
|
|
3432
|
+
Enter: handleEnter,
|
|
3433
|
+
"Mod-Enter": () => this.editor.commands.exitCode(),
|
|
3434
|
+
Backspace: handleBackspace,
|
|
3435
|
+
"Mod-Backspace": handleBackspace,
|
|
3436
|
+
"Shift-Backspace": handleBackspace,
|
|
3437
|
+
Delete: handleDelete,
|
|
3438
|
+
"Mod-Delete": handleDelete,
|
|
3439
|
+
"Mod-a": () => this.editor.commands.selectAll()
|
|
3440
|
+
};
|
|
3441
|
+
const pcKeymap = {
|
|
3442
|
+
...baseKeymap
|
|
3443
|
+
};
|
|
3444
|
+
const macKeymap = {
|
|
3445
|
+
...baseKeymap,
|
|
3446
|
+
"Ctrl-h": handleBackspace,
|
|
3447
|
+
"Alt-Backspace": handleBackspace,
|
|
3448
|
+
"Ctrl-d": handleDelete,
|
|
3449
|
+
"Ctrl-Alt-Backspace": handleDelete,
|
|
3450
|
+
"Alt-Delete": handleDelete,
|
|
3451
|
+
"Alt-d": handleDelete,
|
|
3452
|
+
"Ctrl-a": () => this.editor.commands.selectTextblockStart(),
|
|
3453
|
+
"Ctrl-e": () => this.editor.commands.selectTextblockEnd()
|
|
3454
|
+
};
|
|
3455
|
+
if (isiOS() || isMacOS()) {
|
|
3456
|
+
return macKeymap;
|
|
3457
|
+
}
|
|
3458
|
+
return pcKeymap;
|
|
3459
|
+
},
|
|
3460
|
+
addProseMirrorPlugins() {
|
|
3461
|
+
return [
|
|
3462
|
+
// With this plugin we check if the whole document was selected and deleted.
|
|
3463
|
+
// In this case we will additionally call `clearNodes()` to convert e.g. a heading
|
|
3464
|
+
// to a paragraph if necessary.
|
|
3465
|
+
// This is an alternative to ProseMirror's `AllSelection`, which doesn’t work well
|
|
3466
|
+
// with many other commands.
|
|
3467
|
+
new import_state19.Plugin({
|
|
3468
|
+
key: new import_state19.PluginKey("clearDocument"),
|
|
3469
|
+
appendTransaction: (transactions, oldState, newState) => {
|
|
3470
|
+
if (transactions.some((tr2) => tr2.getMeta("composition"))) {
|
|
3471
|
+
return;
|
|
3472
|
+
}
|
|
3473
|
+
const docChanges = transactions.some((transaction) => transaction.docChanged) && !oldState.doc.eq(newState.doc);
|
|
3474
|
+
const ignoreTr = transactions.some((transaction) => transaction.getMeta("preventClearDocument"));
|
|
3475
|
+
if (!docChanges || ignoreTr) {
|
|
3476
|
+
return;
|
|
3477
|
+
}
|
|
3478
|
+
const { empty, from, to } = oldState.selection;
|
|
3479
|
+
const allFrom = import_state19.Selection.atStart(oldState.doc).from;
|
|
3480
|
+
const allEnd = import_state19.Selection.atEnd(oldState.doc).to;
|
|
3481
|
+
const allWasSelected = from === allFrom && to === allEnd;
|
|
3482
|
+
if (empty || !allWasSelected) {
|
|
3483
|
+
return;
|
|
3484
|
+
}
|
|
3485
|
+
const isEmpty = isNodeEmpty(newState.doc);
|
|
3486
|
+
if (!isEmpty) {
|
|
3487
|
+
return;
|
|
3488
|
+
}
|
|
3489
|
+
const tr = newState.tr;
|
|
3490
|
+
const state = createChainableState({
|
|
3491
|
+
state: newState,
|
|
3492
|
+
transaction: tr
|
|
3493
|
+
});
|
|
3494
|
+
const { commands } = new CommandManager({
|
|
3495
|
+
editor: this.editor,
|
|
3496
|
+
state
|
|
3497
|
+
});
|
|
3498
|
+
commands.clearNodes();
|
|
3499
|
+
if (!tr.steps.length) {
|
|
3500
|
+
return;
|
|
3501
|
+
}
|
|
3502
|
+
return tr;
|
|
3503
|
+
}
|
|
3504
|
+
})
|
|
3505
|
+
];
|
|
3506
|
+
}
|
|
3507
|
+
});
|
|
3508
|
+
var Paste = Extension.create({
|
|
3509
|
+
name: "paste",
|
|
3510
|
+
addProseMirrorPlugins() {
|
|
3511
|
+
return [
|
|
3512
|
+
new import_state20.Plugin({
|
|
3513
|
+
key: new import_state20.PluginKey("tiptapPaste"),
|
|
3514
|
+
props: {
|
|
3515
|
+
handlePaste: (_view, e, slice) => {
|
|
3516
|
+
this.editor.emit("paste", {
|
|
3517
|
+
editor: this.editor,
|
|
3518
|
+
event: e,
|
|
3519
|
+
slice
|
|
3520
|
+
});
|
|
3521
|
+
}
|
|
3522
|
+
}
|
|
3523
|
+
})
|
|
3524
|
+
];
|
|
3525
|
+
}
|
|
3526
|
+
});
|
|
3527
|
+
var Tabindex = Extension.create({
|
|
3528
|
+
name: "tabindex",
|
|
3529
|
+
addProseMirrorPlugins() {
|
|
3530
|
+
return [
|
|
3531
|
+
new import_state21.Plugin({
|
|
3532
|
+
key: new import_state21.PluginKey("tabindex"),
|
|
3533
|
+
props: {
|
|
3534
|
+
attributes: () => this.editor.isEditable ? { tabindex: "0" } : {}
|
|
3535
|
+
}
|
|
3536
|
+
})
|
|
3537
|
+
];
|
|
3538
|
+
}
|
|
3539
|
+
});
|
|
3540
|
+
var TextDirection = Extension.create({
|
|
3541
|
+
name: "textDirection",
|
|
3542
|
+
addOptions() {
|
|
3543
|
+
return {
|
|
3544
|
+
direction: void 0
|
|
3545
|
+
};
|
|
3546
|
+
},
|
|
3547
|
+
addGlobalAttributes() {
|
|
3548
|
+
if (!this.options.direction) {
|
|
3549
|
+
return [];
|
|
3550
|
+
}
|
|
3551
|
+
const { nodeExtensions } = splitExtensions(this.extensions);
|
|
3552
|
+
return [
|
|
3553
|
+
{
|
|
3554
|
+
types: nodeExtensions.filter((extension) => extension.name !== "text").map((extension) => extension.name),
|
|
3555
|
+
attributes: {
|
|
3556
|
+
dir: {
|
|
3557
|
+
default: this.options.direction,
|
|
3558
|
+
parseHTML: (element) => {
|
|
3559
|
+
const dir = element.getAttribute("dir");
|
|
3560
|
+
if (dir && (dir === "ltr" || dir === "rtl" || dir === "auto")) {
|
|
3561
|
+
return dir;
|
|
3562
|
+
}
|
|
3563
|
+
return this.options.direction;
|
|
3564
|
+
},
|
|
3565
|
+
renderHTML: (attributes) => {
|
|
3566
|
+
if (!attributes.dir) {
|
|
3567
|
+
return {};
|
|
3568
|
+
}
|
|
3569
|
+
return {
|
|
3570
|
+
dir: attributes.dir
|
|
3571
|
+
};
|
|
3572
|
+
}
|
|
3573
|
+
}
|
|
3574
|
+
}
|
|
3575
|
+
}
|
|
3576
|
+
];
|
|
3577
|
+
},
|
|
3578
|
+
addProseMirrorPlugins() {
|
|
3579
|
+
return [
|
|
3580
|
+
new import_state22.Plugin({
|
|
3581
|
+
key: new import_state22.PluginKey("textDirection"),
|
|
3582
|
+
props: {
|
|
3583
|
+
attributes: () => {
|
|
3584
|
+
const direction = this.options.direction;
|
|
3585
|
+
if (!direction) {
|
|
3586
|
+
return {};
|
|
3587
|
+
}
|
|
3588
|
+
return {
|
|
3589
|
+
dir: direction
|
|
3590
|
+
};
|
|
3591
|
+
}
|
|
3592
|
+
}
|
|
3593
|
+
})
|
|
3594
|
+
];
|
|
3595
|
+
}
|
|
3596
|
+
});
|
|
3597
|
+
var markdown_exports = {};
|
|
3598
|
+
__export2(markdown_exports, {
|
|
3599
|
+
createAtomBlockMarkdownSpec: () => createAtomBlockMarkdownSpec,
|
|
3600
|
+
createBlockMarkdownSpec: () => createBlockMarkdownSpec,
|
|
3601
|
+
createInlineMarkdownSpec: () => createInlineMarkdownSpec,
|
|
3602
|
+
parseAttributes: () => parseAttributes,
|
|
3603
|
+
parseIndentedBlocks: () => parseIndentedBlocks,
|
|
3604
|
+
renderNestedMarkdownContent: () => renderNestedMarkdownContent,
|
|
3605
|
+
serializeAttributes: () => serializeAttributes
|
|
3606
|
+
});
|
|
3607
|
+
function parseAttributes(attrString) {
|
|
3608
|
+
if (!(attrString == null ? void 0 : attrString.trim())) {
|
|
3609
|
+
return {};
|
|
3610
|
+
}
|
|
3611
|
+
const attributes = {};
|
|
3612
|
+
const quotedStrings = [];
|
|
3613
|
+
const tempString = attrString.replace(/["']([^"']*)["']/g, (match) => {
|
|
3614
|
+
quotedStrings.push(match);
|
|
3615
|
+
return `__QUOTED_${quotedStrings.length - 1}__`;
|
|
3616
|
+
});
|
|
3617
|
+
const classMatches = tempString.match(/(?:^|\s)\.([a-zA-Z][\w-]*)/g);
|
|
3618
|
+
if (classMatches) {
|
|
3619
|
+
const classes = classMatches.map((match) => match.trim().slice(1));
|
|
3620
|
+
attributes.class = classes.join(" ");
|
|
3621
|
+
}
|
|
3622
|
+
const idMatch = tempString.match(/(?:^|\s)#([a-zA-Z][\w-]*)/);
|
|
3623
|
+
if (idMatch) {
|
|
3624
|
+
attributes.id = idMatch[1];
|
|
3625
|
+
}
|
|
3626
|
+
const kvRegex = /([a-zA-Z][\w-]*)\s*=\s*(__QUOTED_\d+__)/g;
|
|
3627
|
+
const kvMatches = Array.from(tempString.matchAll(kvRegex));
|
|
3628
|
+
kvMatches.forEach(([, key, quotedRef]) => {
|
|
3629
|
+
var _a;
|
|
3630
|
+
const quotedIndex = parseInt(((_a = quotedRef.match(/__QUOTED_(\d+)__/)) == null ? void 0 : _a[1]) || "0", 10);
|
|
3631
|
+
const quotedValue = quotedStrings[quotedIndex];
|
|
3632
|
+
if (quotedValue) {
|
|
3633
|
+
attributes[key] = quotedValue.slice(1, -1);
|
|
3634
|
+
}
|
|
3635
|
+
});
|
|
3636
|
+
const cleanString = tempString.replace(/(?:^|\s)\.([a-zA-Z][\w-]*)/g, "").replace(/(?:^|\s)#([a-zA-Z][\w-]*)/g, "").replace(/([a-zA-Z][\w-]*)\s*=\s*__QUOTED_\d+__/g, "").trim();
|
|
3637
|
+
if (cleanString) {
|
|
3638
|
+
const booleanAttrs = cleanString.split(/\s+/).filter(Boolean);
|
|
3639
|
+
booleanAttrs.forEach((attr) => {
|
|
3640
|
+
if (attr.match(/^[a-zA-Z][\w-]*$/)) {
|
|
3641
|
+
attributes[attr] = true;
|
|
3642
|
+
}
|
|
3643
|
+
});
|
|
3644
|
+
}
|
|
3645
|
+
return attributes;
|
|
3646
|
+
}
|
|
3647
|
+
function serializeAttributes(attributes) {
|
|
3648
|
+
if (!attributes || Object.keys(attributes).length === 0) {
|
|
3649
|
+
return "";
|
|
3650
|
+
}
|
|
3651
|
+
const parts = [];
|
|
3652
|
+
if (attributes.class) {
|
|
3653
|
+
const classes = String(attributes.class).split(/\s+/).filter(Boolean);
|
|
3654
|
+
classes.forEach((cls) => parts.push(`.${cls}`));
|
|
3655
|
+
}
|
|
3656
|
+
if (attributes.id) {
|
|
3657
|
+
parts.push(`#${attributes.id}`);
|
|
3658
|
+
}
|
|
3659
|
+
Object.entries(attributes).forEach(([key, value]) => {
|
|
3660
|
+
if (key === "class" || key === "id") {
|
|
3661
|
+
return;
|
|
3662
|
+
}
|
|
3663
|
+
if (value === true) {
|
|
3664
|
+
parts.push(key);
|
|
3665
|
+
} else if (value !== false && value != null) {
|
|
3666
|
+
parts.push(`${key}="${String(value)}"`);
|
|
3667
|
+
}
|
|
3668
|
+
});
|
|
3669
|
+
return parts.join(" ");
|
|
3670
|
+
}
|
|
3671
|
+
function createAtomBlockMarkdownSpec(options) {
|
|
3672
|
+
const {
|
|
3673
|
+
nodeName,
|
|
3674
|
+
name: markdownName,
|
|
3675
|
+
parseAttributes: parseAttributes2 = parseAttributes,
|
|
3676
|
+
serializeAttributes: serializeAttributes2 = serializeAttributes,
|
|
3677
|
+
defaultAttributes = {},
|
|
3678
|
+
requiredAttributes = [],
|
|
3679
|
+
allowedAttributes
|
|
3680
|
+
} = options;
|
|
3681
|
+
const blockName = markdownName || nodeName;
|
|
3682
|
+
const filterAttributes = (attrs) => {
|
|
3683
|
+
if (!allowedAttributes) {
|
|
3684
|
+
return attrs;
|
|
3685
|
+
}
|
|
3686
|
+
const filtered = {};
|
|
3687
|
+
allowedAttributes.forEach((key) => {
|
|
3688
|
+
if (key in attrs) {
|
|
3689
|
+
filtered[key] = attrs[key];
|
|
3690
|
+
}
|
|
3691
|
+
});
|
|
3692
|
+
return filtered;
|
|
3693
|
+
};
|
|
3694
|
+
return {
|
|
3695
|
+
parseMarkdown: (token, h2) => {
|
|
3696
|
+
const attrs = { ...defaultAttributes, ...token.attributes };
|
|
3697
|
+
return h2.createNode(nodeName, attrs, []);
|
|
3698
|
+
},
|
|
3699
|
+
markdownTokenizer: {
|
|
3700
|
+
name: nodeName,
|
|
3701
|
+
level: "block",
|
|
3702
|
+
start(src) {
|
|
3703
|
+
var _a;
|
|
3704
|
+
const regex = new RegExp(`^:::${blockName}(?:\\s|$)`, "m");
|
|
3705
|
+
const index = (_a = src.match(regex)) == null ? void 0 : _a.index;
|
|
3706
|
+
return index !== void 0 ? index : -1;
|
|
3707
|
+
},
|
|
3708
|
+
tokenize(src, _tokens, _lexer) {
|
|
3709
|
+
const regex = new RegExp(`^:::${blockName}(?:\\s+\\{([^}]*)\\})?\\s*:::(?:\\n|$)`);
|
|
3710
|
+
const match = src.match(regex);
|
|
3711
|
+
if (!match) {
|
|
3712
|
+
return void 0;
|
|
3713
|
+
}
|
|
3714
|
+
const attrString = match[1] || "";
|
|
3715
|
+
const attributes = parseAttributes2(attrString);
|
|
3716
|
+
const missingRequired = requiredAttributes.find((required) => !(required in attributes));
|
|
3717
|
+
if (missingRequired) {
|
|
3718
|
+
return void 0;
|
|
3719
|
+
}
|
|
3720
|
+
return {
|
|
3721
|
+
type: nodeName,
|
|
3722
|
+
raw: match[0],
|
|
3723
|
+
attributes
|
|
3724
|
+
};
|
|
3725
|
+
}
|
|
3726
|
+
},
|
|
3727
|
+
renderMarkdown: (node) => {
|
|
3728
|
+
const filteredAttrs = filterAttributes(node.attrs || {});
|
|
3729
|
+
const attrs = serializeAttributes2(filteredAttrs);
|
|
3730
|
+
const attrString = attrs ? ` {${attrs}}` : "";
|
|
3731
|
+
return `:::${blockName}${attrString} :::`;
|
|
3732
|
+
}
|
|
3733
|
+
};
|
|
3734
|
+
}
|
|
3735
|
+
function createBlockMarkdownSpec(options) {
|
|
3736
|
+
const {
|
|
3737
|
+
nodeName,
|
|
3738
|
+
name: markdownName,
|
|
3739
|
+
getContent,
|
|
3740
|
+
parseAttributes: parseAttributes2 = parseAttributes,
|
|
3741
|
+
serializeAttributes: serializeAttributes2 = serializeAttributes,
|
|
3742
|
+
defaultAttributes = {},
|
|
3743
|
+
content = "block",
|
|
3744
|
+
allowedAttributes
|
|
3745
|
+
} = options;
|
|
3746
|
+
const blockName = markdownName || nodeName;
|
|
3747
|
+
const filterAttributes = (attrs) => {
|
|
3748
|
+
if (!allowedAttributes) {
|
|
3749
|
+
return attrs;
|
|
3750
|
+
}
|
|
3751
|
+
const filtered = {};
|
|
3752
|
+
allowedAttributes.forEach((key) => {
|
|
3753
|
+
if (key in attrs) {
|
|
3754
|
+
filtered[key] = attrs[key];
|
|
3755
|
+
}
|
|
3756
|
+
});
|
|
3757
|
+
return filtered;
|
|
3758
|
+
};
|
|
3759
|
+
return {
|
|
3760
|
+
parseMarkdown: (token, h2) => {
|
|
3761
|
+
let nodeContent;
|
|
3762
|
+
if (getContent) {
|
|
3763
|
+
const contentResult = getContent(token);
|
|
3764
|
+
nodeContent = typeof contentResult === "string" ? [{ type: "text", text: contentResult }] : contentResult;
|
|
3765
|
+
} else if (content === "block") {
|
|
3766
|
+
nodeContent = h2.parseChildren(token.tokens || []);
|
|
3767
|
+
} else {
|
|
3768
|
+
nodeContent = h2.parseInline(token.tokens || []);
|
|
3769
|
+
}
|
|
3770
|
+
const attrs = { ...defaultAttributes, ...token.attributes };
|
|
3771
|
+
return h2.createNode(nodeName, attrs, nodeContent);
|
|
3772
|
+
},
|
|
3773
|
+
markdownTokenizer: {
|
|
3774
|
+
name: nodeName,
|
|
3775
|
+
level: "block",
|
|
3776
|
+
start(src) {
|
|
3777
|
+
var _a;
|
|
3778
|
+
const regex = new RegExp(`^:::${blockName}`, "m");
|
|
3779
|
+
const index = (_a = src.match(regex)) == null ? void 0 : _a.index;
|
|
3780
|
+
return index !== void 0 ? index : -1;
|
|
3781
|
+
},
|
|
3782
|
+
tokenize(src, _tokens, lexer) {
|
|
3783
|
+
var _a;
|
|
3784
|
+
const openingRegex = new RegExp(`^:::${blockName}(?:\\s+\\{([^}]*)\\})?\\s*\\n`);
|
|
3785
|
+
const openingMatch = src.match(openingRegex);
|
|
3786
|
+
if (!openingMatch) {
|
|
3787
|
+
return void 0;
|
|
3788
|
+
}
|
|
3789
|
+
const [openingTag, attrString = ""] = openingMatch;
|
|
3790
|
+
const attributes = parseAttributes2(attrString);
|
|
3791
|
+
let level = 1;
|
|
3792
|
+
const position = openingTag.length;
|
|
3793
|
+
let matchedContent = "";
|
|
3794
|
+
const blockPattern = /^:::([\w-]*)(\s.*)?/gm;
|
|
3795
|
+
const remaining = src.slice(position);
|
|
3796
|
+
blockPattern.lastIndex = 0;
|
|
3797
|
+
for (; ; ) {
|
|
3798
|
+
const match = blockPattern.exec(remaining);
|
|
3799
|
+
if (match === null) {
|
|
3800
|
+
break;
|
|
3801
|
+
}
|
|
3802
|
+
const matchPos = match.index;
|
|
3803
|
+
const blockType = match[1];
|
|
3804
|
+
if ((_a = match[2]) == null ? void 0 : _a.endsWith(":::")) {
|
|
3805
|
+
continue;
|
|
3806
|
+
}
|
|
3807
|
+
if (blockType) {
|
|
3808
|
+
level += 1;
|
|
3809
|
+
} else {
|
|
3810
|
+
level -= 1;
|
|
3811
|
+
if (level === 0) {
|
|
3812
|
+
const rawContent = remaining.slice(0, matchPos);
|
|
3813
|
+
matchedContent = rawContent.trim();
|
|
3814
|
+
const fullMatch = src.slice(0, position + matchPos + match[0].length);
|
|
3815
|
+
let contentTokens = [];
|
|
3816
|
+
if (matchedContent) {
|
|
3817
|
+
if (content === "block") {
|
|
3818
|
+
contentTokens = lexer.blockTokens(rawContent);
|
|
3819
|
+
contentTokens.forEach((token) => {
|
|
3820
|
+
if (token.text && (!token.tokens || token.tokens.length === 0)) {
|
|
3821
|
+
token.tokens = lexer.inlineTokens(token.text);
|
|
3822
|
+
}
|
|
3823
|
+
});
|
|
3824
|
+
while (contentTokens.length > 0) {
|
|
3825
|
+
const lastToken = contentTokens[contentTokens.length - 1];
|
|
3826
|
+
if (lastToken.type === "paragraph" && (!lastToken.text || lastToken.text.trim() === "")) {
|
|
3827
|
+
contentTokens.pop();
|
|
3828
|
+
} else {
|
|
3829
|
+
break;
|
|
3830
|
+
}
|
|
3831
|
+
}
|
|
3832
|
+
} else {
|
|
3833
|
+
contentTokens = lexer.inlineTokens(matchedContent);
|
|
3834
|
+
}
|
|
3835
|
+
}
|
|
3836
|
+
return {
|
|
3837
|
+
type: nodeName,
|
|
3838
|
+
raw: fullMatch,
|
|
3839
|
+
attributes,
|
|
3840
|
+
content: matchedContent,
|
|
3841
|
+
tokens: contentTokens
|
|
3842
|
+
};
|
|
3843
|
+
}
|
|
3844
|
+
}
|
|
3845
|
+
}
|
|
3846
|
+
return void 0;
|
|
3847
|
+
}
|
|
3848
|
+
},
|
|
3849
|
+
renderMarkdown: (node, h2) => {
|
|
3850
|
+
const filteredAttrs = filterAttributes(node.attrs || {});
|
|
3851
|
+
const attrs = serializeAttributes2(filteredAttrs);
|
|
3852
|
+
const attrString = attrs ? ` {${attrs}}` : "";
|
|
3853
|
+
const renderedContent = h2.renderChildren(node.content || [], "\n\n");
|
|
3854
|
+
return `:::${blockName}${attrString}
|
|
3855
|
+
|
|
3856
|
+
${renderedContent}
|
|
3857
|
+
|
|
3858
|
+
:::`;
|
|
3859
|
+
}
|
|
3860
|
+
};
|
|
3861
|
+
}
|
|
3862
|
+
function parseShortcodeAttributes(attrString) {
|
|
3863
|
+
if (!attrString.trim()) {
|
|
3864
|
+
return {};
|
|
3865
|
+
}
|
|
3866
|
+
const attributes = {};
|
|
3867
|
+
const regex = /(\w+)=(?:"([^"]*)"|'([^']*)')/g;
|
|
3868
|
+
let match = regex.exec(attrString);
|
|
3869
|
+
while (match !== null) {
|
|
3870
|
+
const [, key, doubleQuoted, singleQuoted] = match;
|
|
3871
|
+
attributes[key] = doubleQuoted || singleQuoted;
|
|
3872
|
+
match = regex.exec(attrString);
|
|
3873
|
+
}
|
|
3874
|
+
return attributes;
|
|
3875
|
+
}
|
|
3876
|
+
function serializeShortcodeAttributes(attrs) {
|
|
3877
|
+
return Object.entries(attrs).filter(([, value]) => value !== void 0 && value !== null).map(([key, value]) => `${key}="${value}"`).join(" ");
|
|
3878
|
+
}
|
|
3879
|
+
function createInlineMarkdownSpec(options) {
|
|
3880
|
+
const {
|
|
3881
|
+
nodeName,
|
|
3882
|
+
name: shortcodeName,
|
|
3883
|
+
getContent,
|
|
3884
|
+
parseAttributes: parseAttributes2 = parseShortcodeAttributes,
|
|
3885
|
+
serializeAttributes: serializeAttributes2 = serializeShortcodeAttributes,
|
|
3886
|
+
defaultAttributes = {},
|
|
3887
|
+
selfClosing = false,
|
|
3888
|
+
allowedAttributes
|
|
3889
|
+
} = options;
|
|
3890
|
+
const shortcode = shortcodeName || nodeName;
|
|
3891
|
+
const filterAttributes = (attrs) => {
|
|
3892
|
+
if (!allowedAttributes) {
|
|
3893
|
+
return attrs;
|
|
3894
|
+
}
|
|
3895
|
+
const filtered = {};
|
|
3896
|
+
allowedAttributes.forEach((attr) => {
|
|
3897
|
+
const attrName = typeof attr === "string" ? attr : attr.name;
|
|
3898
|
+
const skipIfDefault = typeof attr === "string" ? void 0 : attr.skipIfDefault;
|
|
3899
|
+
if (attrName in attrs) {
|
|
3900
|
+
const value = attrs[attrName];
|
|
3901
|
+
if (skipIfDefault !== void 0 && value === skipIfDefault) {
|
|
3902
|
+
return;
|
|
3903
|
+
}
|
|
3904
|
+
filtered[attrName] = value;
|
|
3905
|
+
}
|
|
3906
|
+
});
|
|
3907
|
+
return filtered;
|
|
3908
|
+
};
|
|
3909
|
+
const escapedShortcode = shortcode.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
3910
|
+
return {
|
|
3911
|
+
parseMarkdown: (token, h2) => {
|
|
3912
|
+
const attrs = { ...defaultAttributes, ...token.attributes };
|
|
3913
|
+
if (selfClosing) {
|
|
3914
|
+
return h2.createNode(nodeName, attrs);
|
|
3915
|
+
}
|
|
3916
|
+
const content = getContent ? getContent(token) : token.content || "";
|
|
3917
|
+
if (content) {
|
|
3918
|
+
return h2.createNode(nodeName, attrs, [h2.createTextNode(content)]);
|
|
3919
|
+
}
|
|
3920
|
+
return h2.createNode(nodeName, attrs, []);
|
|
3921
|
+
},
|
|
3922
|
+
markdownTokenizer: {
|
|
3923
|
+
name: nodeName,
|
|
3924
|
+
level: "inline",
|
|
3925
|
+
start(src) {
|
|
3926
|
+
const startPattern = selfClosing ? new RegExp(`\\[${escapedShortcode}\\s*[^\\]]*\\]`) : new RegExp(`\\[${escapedShortcode}\\s*[^\\]]*\\][\\s\\S]*?\\[\\/${escapedShortcode}\\]`);
|
|
3927
|
+
const match = src.match(startPattern);
|
|
3928
|
+
const index = match == null ? void 0 : match.index;
|
|
3929
|
+
return index !== void 0 ? index : -1;
|
|
3930
|
+
},
|
|
3931
|
+
tokenize(src, _tokens, _lexer) {
|
|
3932
|
+
const tokenPattern = selfClosing ? new RegExp(`^\\[${escapedShortcode}\\s*([^\\]]*)\\]`) : new RegExp(`^\\[${escapedShortcode}\\s*([^\\]]*)\\]([\\s\\S]*?)\\[\\/${escapedShortcode}\\]`);
|
|
3933
|
+
const match = src.match(tokenPattern);
|
|
3934
|
+
if (!match) {
|
|
3935
|
+
return void 0;
|
|
3936
|
+
}
|
|
3937
|
+
let content = "";
|
|
3938
|
+
let attrString = "";
|
|
3939
|
+
if (selfClosing) {
|
|
3940
|
+
const [, attrs] = match;
|
|
3941
|
+
attrString = attrs;
|
|
3942
|
+
} else {
|
|
3943
|
+
const [, attrs, contentMatch] = match;
|
|
3944
|
+
attrString = attrs;
|
|
3945
|
+
content = contentMatch || "";
|
|
3946
|
+
}
|
|
3947
|
+
const attributes = parseAttributes2(attrString.trim());
|
|
3948
|
+
return {
|
|
3949
|
+
type: nodeName,
|
|
3950
|
+
raw: match[0],
|
|
3951
|
+
content: content.trim(),
|
|
3952
|
+
attributes
|
|
3953
|
+
};
|
|
3954
|
+
}
|
|
3955
|
+
},
|
|
3956
|
+
renderMarkdown: (node) => {
|
|
3957
|
+
let content = "";
|
|
3958
|
+
if (getContent) {
|
|
3959
|
+
content = getContent(node);
|
|
3960
|
+
} else if (node.content && node.content.length > 0) {
|
|
3961
|
+
content = node.content.filter((child) => child.type === "text").map((child) => child.text).join("");
|
|
3962
|
+
}
|
|
3963
|
+
const filteredAttrs = filterAttributes(node.attrs || {});
|
|
3964
|
+
const attrs = serializeAttributes2(filteredAttrs);
|
|
3965
|
+
const attrString = attrs ? ` ${attrs}` : "";
|
|
3966
|
+
if (selfClosing) {
|
|
3967
|
+
return `[${shortcode}${attrString}]`;
|
|
3968
|
+
}
|
|
3969
|
+
return `[${shortcode}${attrString}]${content}[/${shortcode}]`;
|
|
3970
|
+
}
|
|
3971
|
+
};
|
|
3972
|
+
}
|
|
3973
|
+
function parseIndentedBlocks(src, config, lexer) {
|
|
3974
|
+
var _a, _b, _c, _d;
|
|
3975
|
+
const lines = src.split("\n");
|
|
3976
|
+
const items = [];
|
|
3977
|
+
let totalRaw = "";
|
|
3978
|
+
let i = 0;
|
|
3979
|
+
const baseIndentSize = config.baseIndentSize || 2;
|
|
3980
|
+
while (i < lines.length) {
|
|
3981
|
+
const currentLine = lines[i];
|
|
3982
|
+
const itemMatch = currentLine.match(config.itemPattern);
|
|
3983
|
+
if (!itemMatch) {
|
|
3984
|
+
if (items.length > 0) {
|
|
3985
|
+
break;
|
|
3986
|
+
} else if (currentLine.trim() === "") {
|
|
3987
|
+
i += 1;
|
|
3988
|
+
totalRaw = `${totalRaw}${currentLine}
|
|
3989
|
+
`;
|
|
3990
|
+
continue;
|
|
3991
|
+
} else {
|
|
3992
|
+
return void 0;
|
|
3993
|
+
}
|
|
3994
|
+
}
|
|
3995
|
+
const itemData = config.extractItemData(itemMatch);
|
|
3996
|
+
const { indentLevel, mainContent } = itemData;
|
|
3997
|
+
totalRaw = `${totalRaw}${currentLine}
|
|
3998
|
+
`;
|
|
3999
|
+
const itemContent = [mainContent];
|
|
4000
|
+
i += 1;
|
|
4001
|
+
while (i < lines.length) {
|
|
4002
|
+
const nextLine = lines[i];
|
|
4003
|
+
if (nextLine.trim() === "") {
|
|
4004
|
+
const nextNonEmptyIndex = lines.slice(i + 1).findIndex((l) => l.trim() !== "");
|
|
4005
|
+
if (nextNonEmptyIndex === -1) {
|
|
4006
|
+
break;
|
|
4007
|
+
}
|
|
4008
|
+
const nextNonEmpty = lines[i + 1 + nextNonEmptyIndex];
|
|
4009
|
+
const nextIndent2 = ((_b = (_a = nextNonEmpty.match(/^(\s*)/)) == null ? void 0 : _a[1]) == null ? void 0 : _b.length) || 0;
|
|
4010
|
+
if (nextIndent2 > indentLevel) {
|
|
4011
|
+
itemContent.push(nextLine);
|
|
4012
|
+
totalRaw = `${totalRaw}${nextLine}
|
|
4013
|
+
`;
|
|
4014
|
+
i += 1;
|
|
4015
|
+
continue;
|
|
4016
|
+
} else {
|
|
4017
|
+
break;
|
|
4018
|
+
}
|
|
4019
|
+
}
|
|
4020
|
+
const nextIndent = ((_d = (_c = nextLine.match(/^(\s*)/)) == null ? void 0 : _c[1]) == null ? void 0 : _d.length) || 0;
|
|
4021
|
+
if (nextIndent > indentLevel) {
|
|
4022
|
+
itemContent.push(nextLine);
|
|
4023
|
+
totalRaw = `${totalRaw}${nextLine}
|
|
4024
|
+
`;
|
|
4025
|
+
i += 1;
|
|
4026
|
+
} else {
|
|
4027
|
+
break;
|
|
4028
|
+
}
|
|
4029
|
+
}
|
|
4030
|
+
let nestedTokens;
|
|
4031
|
+
const nestedContent = itemContent.slice(1);
|
|
4032
|
+
if (nestedContent.length > 0) {
|
|
4033
|
+
const dedentedNested = nestedContent.map((nestedLine) => nestedLine.slice(indentLevel + baseIndentSize)).join("\n");
|
|
4034
|
+
if (dedentedNested.trim()) {
|
|
4035
|
+
if (config.customNestedParser) {
|
|
4036
|
+
nestedTokens = config.customNestedParser(dedentedNested);
|
|
4037
|
+
} else {
|
|
4038
|
+
nestedTokens = lexer.blockTokens(dedentedNested);
|
|
4039
|
+
}
|
|
4040
|
+
}
|
|
4041
|
+
}
|
|
4042
|
+
const token = config.createToken(itemData, nestedTokens);
|
|
4043
|
+
items.push(token);
|
|
4044
|
+
}
|
|
4045
|
+
if (items.length === 0) {
|
|
4046
|
+
return void 0;
|
|
4047
|
+
}
|
|
4048
|
+
return {
|
|
4049
|
+
items,
|
|
4050
|
+
raw: totalRaw
|
|
4051
|
+
};
|
|
4052
|
+
}
|
|
4053
|
+
function renderNestedMarkdownContent(node, h2, prefixOrGenerator, ctx) {
|
|
4054
|
+
if (!node || !Array.isArray(node.content)) {
|
|
4055
|
+
return "";
|
|
4056
|
+
}
|
|
4057
|
+
const prefix = typeof prefixOrGenerator === "function" ? prefixOrGenerator(ctx) : prefixOrGenerator;
|
|
4058
|
+
const [content, ...children] = node.content;
|
|
4059
|
+
const mainContent = h2.renderChildren([content]);
|
|
4060
|
+
const output = [`${prefix}${mainContent}`];
|
|
4061
|
+
if (children && children.length > 0) {
|
|
4062
|
+
children.forEach((child) => {
|
|
4063
|
+
const childContent = h2.renderChildren([child]);
|
|
4064
|
+
if (childContent) {
|
|
4065
|
+
const indentedChild = childContent.split("\n").map((line) => line ? h2.indent(line) : "").join("\n");
|
|
4066
|
+
output.push(indentedChild);
|
|
4067
|
+
}
|
|
4068
|
+
});
|
|
4069
|
+
}
|
|
4070
|
+
return output.join("\n");
|
|
4071
|
+
}
|
|
4072
|
+
function updateMarkViewAttributes(checkMark, editor, attrs = {}) {
|
|
4073
|
+
const { state } = editor;
|
|
4074
|
+
const { doc, tr } = state;
|
|
4075
|
+
const thisMark = checkMark;
|
|
4076
|
+
doc.descendants((node, pos) => {
|
|
4077
|
+
const from = tr.mapping.map(pos);
|
|
4078
|
+
const to = tr.mapping.map(pos) + node.nodeSize;
|
|
4079
|
+
let foundMark = null;
|
|
4080
|
+
node.marks.forEach((mark) => {
|
|
4081
|
+
if (mark !== thisMark) {
|
|
4082
|
+
return false;
|
|
4083
|
+
}
|
|
4084
|
+
foundMark = mark;
|
|
4085
|
+
});
|
|
4086
|
+
if (!foundMark) {
|
|
4087
|
+
return;
|
|
4088
|
+
}
|
|
4089
|
+
let needsUpdate = false;
|
|
4090
|
+
Object.keys(attrs).forEach((k) => {
|
|
4091
|
+
if (attrs[k] !== foundMark.attrs[k]) {
|
|
4092
|
+
needsUpdate = true;
|
|
4093
|
+
}
|
|
4094
|
+
});
|
|
4095
|
+
if (needsUpdate) {
|
|
4096
|
+
const updatedMark = checkMark.type.create({
|
|
4097
|
+
...checkMark.attrs,
|
|
4098
|
+
...attrs
|
|
4099
|
+
});
|
|
4100
|
+
tr.removeMark(from, to, checkMark.type);
|
|
4101
|
+
tr.addMark(from, to, updatedMark);
|
|
4102
|
+
}
|
|
4103
|
+
});
|
|
4104
|
+
if (tr.docChanged) {
|
|
4105
|
+
editor.view.dispatch(tr);
|
|
4106
|
+
}
|
|
4107
|
+
}
|
|
4108
|
+
var Node3 = class _Node extends Extendable {
|
|
4109
|
+
constructor() {
|
|
4110
|
+
super(...arguments);
|
|
4111
|
+
this.type = "node";
|
|
4112
|
+
}
|
|
4113
|
+
/**
|
|
4114
|
+
* Create a new Node instance
|
|
4115
|
+
* @param config - Node configuration object or a function that returns a configuration object
|
|
4116
|
+
*/
|
|
4117
|
+
static create(config = {}) {
|
|
4118
|
+
const resolvedConfig = typeof config === "function" ? config() : config;
|
|
4119
|
+
return new _Node(resolvedConfig);
|
|
4120
|
+
}
|
|
4121
|
+
configure(options) {
|
|
4122
|
+
return super.configure(options);
|
|
4123
|
+
}
|
|
4124
|
+
extend(extendedConfig) {
|
|
4125
|
+
const resolvedConfig = typeof extendedConfig === "function" ? extendedConfig() : extendedConfig;
|
|
4126
|
+
return super.extend(resolvedConfig);
|
|
4127
|
+
}
|
|
4128
|
+
};
|
|
4129
|
+
|
|
4130
|
+
// src/extensions/callout.ts
|
|
4131
|
+
var CALLOUT_ARIA_LABELS = {
|
|
4132
|
+
success: "\u6210\u529F\u63D0\u793A",
|
|
4133
|
+
warning: "\u8B66\u544A\u63D0\u793A",
|
|
4134
|
+
error: "\u932F\u8AA4\u63D0\u793A",
|
|
4135
|
+
info: "\u8CC7\u8A0A\u63D0\u793A"
|
|
4136
|
+
};
|
|
4137
|
+
var Callout = Node3.create({
|
|
4138
|
+
name: "callout",
|
|
4139
|
+
group: "block",
|
|
4140
|
+
content: "block+",
|
|
4141
|
+
defining: true,
|
|
4142
|
+
addOptions() {
|
|
4143
|
+
return {
|
|
4144
|
+
HTMLAttributes: {}
|
|
4145
|
+
};
|
|
4146
|
+
},
|
|
4147
|
+
addAttributes() {
|
|
4148
|
+
return {
|
|
4149
|
+
type: {
|
|
4150
|
+
default: "info",
|
|
4151
|
+
parseHTML: (element) => element.getAttribute("data-type"),
|
|
4152
|
+
renderHTML: (attributes) => ({
|
|
4153
|
+
"data-type": attributes.type
|
|
4154
|
+
})
|
|
4155
|
+
}
|
|
4156
|
+
};
|
|
4157
|
+
},
|
|
4158
|
+
parseHTML() {
|
|
4159
|
+
return [
|
|
4160
|
+
{
|
|
4161
|
+
tag: "div[data-callout]"
|
|
4162
|
+
}
|
|
4163
|
+
];
|
|
4164
|
+
},
|
|
4165
|
+
renderHTML({ node, HTMLAttributes }) {
|
|
4166
|
+
const type = node.attrs.type || "info";
|
|
4167
|
+
return [
|
|
4168
|
+
"div",
|
|
4169
|
+
mergeAttributes(this.options.HTMLAttributes, HTMLAttributes, {
|
|
4170
|
+
"data-callout": "",
|
|
4171
|
+
"class": `callout callout-${type}`,
|
|
4172
|
+
"role": "note",
|
|
4173
|
+
"aria-label": CALLOUT_ARIA_LABELS[type]
|
|
4174
|
+
}),
|
|
4175
|
+
0
|
|
4176
|
+
];
|
|
4177
|
+
},
|
|
4178
|
+
addCommands() {
|
|
4179
|
+
return {
|
|
4180
|
+
setCallout: (attributes) => ({ commands }) => {
|
|
4181
|
+
return commands.wrapIn(this.name, attributes);
|
|
4182
|
+
},
|
|
4183
|
+
toggleCallout: (attributes) => ({ commands }) => {
|
|
4184
|
+
return commands.toggleWrap(this.name, attributes);
|
|
4185
|
+
},
|
|
4186
|
+
unsetCallout: () => ({ commands }) => {
|
|
4187
|
+
return commands.lift(this.name);
|
|
4188
|
+
}
|
|
4189
|
+
};
|
|
4190
|
+
}
|
|
4191
|
+
});
|
|
4192
|
+
|
|
4193
|
+
// src/components/Toolbar.tsx
|
|
4194
|
+
var import_react2 = require("react");
|
|
4195
|
+
|
|
4196
|
+
// src/ui/button.tsx
|
|
4197
|
+
var React = __toESM(require("react"), 1);
|
|
4198
|
+
|
|
4199
|
+
// src/lib/utils.ts
|
|
4200
|
+
var import_clsx = require("clsx");
|
|
4201
|
+
var import_tailwind_merge = require("tailwind-merge");
|
|
4202
|
+
function cn(...inputs) {
|
|
4203
|
+
return (0, import_tailwind_merge.twMerge)((0, import_clsx.clsx)(inputs));
|
|
4204
|
+
}
|
|
4205
|
+
|
|
4206
|
+
// src/ui/button.tsx
|
|
4207
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
4208
|
+
var Button = React.forwardRef(
|
|
4209
|
+
({ className, variant = "default", size = "default", ...props }, ref) => {
|
|
4210
|
+
const variantStyles = {
|
|
4211
|
+
default: "bg-[var(--background)] text-[var(--foreground)] hover:bg-[var(--accent)]",
|
|
4212
|
+
ghost: "hover:bg-[var(--accent)] hover:text-[var(--accent-foreground)]",
|
|
4213
|
+
outline: "border border-[var(--border)] bg-transparent hover:bg-[var(--accent)]"
|
|
4214
|
+
};
|
|
4215
|
+
const sizeStyles = {
|
|
4216
|
+
default: "h-9 px-4 py-2",
|
|
4217
|
+
sm: "h-8 px-3 text-xs",
|
|
4218
|
+
lg: "h-10 px-8"
|
|
4219
|
+
};
|
|
4220
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
4221
|
+
"button",
|
|
4222
|
+
{
|
|
4223
|
+
className: cn(
|
|
4224
|
+
"inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors",
|
|
4225
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--ring)]",
|
|
4226
|
+
"disabled:pointer-events-none disabled:opacity-50",
|
|
4227
|
+
variantStyles[variant],
|
|
4228
|
+
sizeStyles[size],
|
|
4229
|
+
className
|
|
4230
|
+
),
|
|
4231
|
+
ref,
|
|
4232
|
+
...props
|
|
4233
|
+
}
|
|
4234
|
+
);
|
|
4235
|
+
}
|
|
4236
|
+
);
|
|
4237
|
+
Button.displayName = "Button";
|
|
4238
|
+
|
|
4239
|
+
// src/ui/toggle.tsx
|
|
4240
|
+
var React2 = __toESM(require("react"), 1);
|
|
4241
|
+
var TogglePrimitive = __toESM(require("@radix-ui/react-toggle"), 1);
|
|
4242
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
4243
|
+
var Toggle = React2.forwardRef(
|
|
4244
|
+
({ className, size = "default", ...props }, ref) => {
|
|
4245
|
+
const sizeStyles = {
|
|
4246
|
+
default: "h-9 px-3",
|
|
4247
|
+
sm: "h-8 px-2"
|
|
4248
|
+
};
|
|
4249
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
4250
|
+
TogglePrimitive.Root,
|
|
4251
|
+
{
|
|
4252
|
+
ref,
|
|
4253
|
+
className: cn(
|
|
4254
|
+
"inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors",
|
|
4255
|
+
"hover:bg-[var(--accent)] hover:text-[var(--accent-foreground)]",
|
|
4256
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--ring)]",
|
|
4257
|
+
"disabled:pointer-events-none disabled:opacity-50",
|
|
4258
|
+
"data-[state=on]:bg-[var(--accent)] data-[state=on]:text-[var(--accent-foreground)]",
|
|
4259
|
+
sizeStyles[size],
|
|
4260
|
+
className
|
|
4261
|
+
),
|
|
4262
|
+
...props
|
|
4263
|
+
}
|
|
4264
|
+
);
|
|
4265
|
+
}
|
|
4266
|
+
);
|
|
4267
|
+
Toggle.displayName = TogglePrimitive.Root.displayName;
|
|
4268
|
+
|
|
4269
|
+
// src/components/ToolbarButton.tsx
|
|
4270
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
4271
|
+
function ToolbarButton({
|
|
4272
|
+
pressed,
|
|
4273
|
+
onPressedChange,
|
|
4274
|
+
disabled,
|
|
4275
|
+
children,
|
|
4276
|
+
title
|
|
4277
|
+
}) {
|
|
4278
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
4279
|
+
Toggle,
|
|
4280
|
+
{
|
|
4281
|
+
size: "sm",
|
|
4282
|
+
pressed,
|
|
4283
|
+
onPressedChange,
|
|
4284
|
+
disabled,
|
|
4285
|
+
title,
|
|
4286
|
+
className: "h-9 w-9 p-0 border-0 bg-transparent rounded-lg hover:bg-muted data-[state=on]:bg-zinc-900 data-[state=on]:text-white dark:data-[state=on]:bg-zinc-100 dark:data-[state=on]:text-zinc-900 disabled:opacity-30",
|
|
4287
|
+
children
|
|
4288
|
+
}
|
|
4289
|
+
);
|
|
4290
|
+
}
|
|
4291
|
+
|
|
4292
|
+
// src/components/ToolbarDivider.tsx
|
|
4293
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
4294
|
+
function ToolbarDivider() {
|
|
4295
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "w-px h-5 bg-border mx-1.5" });
|
|
4296
|
+
}
|
|
4297
|
+
|
|
4298
|
+
// src/ui/dropdown-menu.tsx
|
|
4299
|
+
var React3 = __toESM(require("react"), 1);
|
|
4300
|
+
var DropdownMenuPrimitive = __toESM(require("@radix-ui/react-dropdown-menu"), 1);
|
|
4301
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
4302
|
+
var DropdownMenu = DropdownMenuPrimitive.Root;
|
|
4303
|
+
var DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
|
|
4304
|
+
var DropdownMenuContent = React3.forwardRef(({ className, sideOffset = 4, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(DropdownMenuPrimitive.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
4305
|
+
DropdownMenuPrimitive.Content,
|
|
4306
|
+
{
|
|
4307
|
+
ref,
|
|
4308
|
+
sideOffset,
|
|
4309
|
+
className: cn(
|
|
4310
|
+
"z-50 min-w-[8rem] overflow-hidden rounded-md border border-[var(--border)] bg-[var(--popover)] p-1 text-[var(--popover-foreground)] shadow-md",
|
|
4311
|
+
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95",
|
|
4312
|
+
"data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
|
4313
|
+
className
|
|
4314
|
+
),
|
|
4315
|
+
...props
|
|
4316
|
+
}
|
|
4317
|
+
) }));
|
|
4318
|
+
DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;
|
|
4319
|
+
var DropdownMenuItem = React3.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
4320
|
+
DropdownMenuPrimitive.Item,
|
|
4321
|
+
{
|
|
4322
|
+
ref,
|
|
4323
|
+
className: cn(
|
|
4324
|
+
"relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors",
|
|
4325
|
+
"focus:bg-[var(--accent)] focus:text-[var(--accent-foreground)]",
|
|
4326
|
+
"data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
|
4327
|
+
className
|
|
4328
|
+
),
|
|
4329
|
+
...props
|
|
4330
|
+
}
|
|
4331
|
+
));
|
|
4332
|
+
DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;
|
|
4333
|
+
var DropdownMenuSeparator = React3.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
4334
|
+
DropdownMenuPrimitive.Separator,
|
|
4335
|
+
{
|
|
4336
|
+
ref,
|
|
4337
|
+
className: cn("-mx-1 my-1 h-px bg-[var(--border)]", className),
|
|
4338
|
+
...props
|
|
4339
|
+
}
|
|
4340
|
+
));
|
|
4341
|
+
DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName;
|
|
4342
|
+
|
|
4343
|
+
// src/components/HeadingDropdown.tsx
|
|
4344
|
+
var import_lucide_react = require("lucide-react");
|
|
4345
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
4346
|
+
function HeadingDropdown({ editor, iconSize = "h-4 w-4" }) {
|
|
4347
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(DropdownMenu, { children: [
|
|
4348
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Button, { variant: "ghost", size: "sm", className: "h-8 px-2 gap-1 font-normal", children: [
|
|
4349
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "text-sm font-semibold", children: "H" }),
|
|
4350
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react.ChevronDown, { className: "h-3 w-3" })
|
|
4351
|
+
] }) }),
|
|
4352
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(DropdownMenuContent, { align: "start", children: [
|
|
4353
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(DropdownMenuItem, { onClick: () => editor.chain().focus().toggleHeading({ level: 1 }).run(), children: [
|
|
4354
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react.Heading1, { className: cn(iconSize, "mr-2") }),
|
|
4355
|
+
"\u6A19\u984C 1"
|
|
4356
|
+
] }),
|
|
4357
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(DropdownMenuItem, { onClick: () => editor.chain().focus().toggleHeading({ level: 2 }).run(), children: [
|
|
4358
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react.Heading2, { className: cn(iconSize, "mr-2") }),
|
|
4359
|
+
"\u6A19\u984C 2"
|
|
4360
|
+
] }),
|
|
4361
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(DropdownMenuItem, { onClick: () => editor.chain().focus().toggleHeading({ level: 3 }).run(), children: [
|
|
4362
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react.Heading3, { className: cn(iconSize, "mr-2") }),
|
|
4363
|
+
"\u6A19\u984C 3"
|
|
4364
|
+
] }),
|
|
4365
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(DropdownMenuItem, { onClick: () => editor.chain().focus().setParagraph().run(), children: "\u5167\u6587" })
|
|
4366
|
+
] })
|
|
4367
|
+
] });
|
|
4368
|
+
}
|
|
4369
|
+
|
|
4370
|
+
// src/components/ListDropdown.tsx
|
|
4371
|
+
var import_lucide_react2 = require("lucide-react");
|
|
4372
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
4373
|
+
function ListDropdown({ editor, iconSize = "h-4 w-4" }) {
|
|
4374
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(DropdownMenu, { children: [
|
|
4375
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Button, { variant: "ghost", size: "sm", className: "h-8 px-2 gap-1", children: [
|
|
4376
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_lucide_react2.List, { className: iconSize }),
|
|
4377
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_lucide_react2.ChevronDown, { className: "h-3 w-3" })
|
|
4378
|
+
] }) }),
|
|
4379
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(DropdownMenuContent, { align: "start", children: [
|
|
4380
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(DropdownMenuItem, { onClick: () => editor.chain().focus().toggleBulletList().run(), children: [
|
|
4381
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_lucide_react2.List, { className: cn(iconSize, "mr-2") }),
|
|
4382
|
+
"\u9805\u76EE\u6E05\u55AE"
|
|
4383
|
+
] }),
|
|
4384
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(DropdownMenuItem, { onClick: () => editor.chain().focus().toggleOrderedList().run(), children: [
|
|
4385
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_lucide_react2.ListOrdered, { className: cn(iconSize, "mr-2") }),
|
|
4386
|
+
"\u7DE8\u865F\u6E05\u55AE"
|
|
4387
|
+
] }),
|
|
4388
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(DropdownMenuItem, { onClick: () => editor.chain().focus().toggleTaskList().run(), children: [
|
|
4389
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_lucide_react2.ListTodo, { className: cn(iconSize, "mr-2") }),
|
|
4390
|
+
"\u4EFB\u52D9\u6E05\u55AE"
|
|
4391
|
+
] })
|
|
4392
|
+
] })
|
|
4393
|
+
] });
|
|
4394
|
+
}
|
|
4395
|
+
|
|
4396
|
+
// src/components/TableDropdown.tsx
|
|
4397
|
+
var import_lucide_react3 = require("lucide-react");
|
|
4398
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
4399
|
+
function TableDropdown({ editor, iconSize = "h-4 w-4" }) {
|
|
4400
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(DropdownMenu, { children: [
|
|
4401
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Button, { variant: "ghost", size: "sm", className: "h-8 px-2 gap-1", children: [
|
|
4402
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_lucide_react3.Table, { className: iconSize }),
|
|
4403
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_lucide_react3.ChevronDown, { className: "h-3 w-3" })
|
|
4404
|
+
] }) }),
|
|
4405
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(DropdownMenuContent, { align: "start", children: [
|
|
4406
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
4407
|
+
DropdownMenuItem,
|
|
4408
|
+
{
|
|
4409
|
+
onClick: () => editor.chain().focus().insertTable({ rows: 3, cols: 3, withHeaderRow: true }).run(),
|
|
4410
|
+
children: [
|
|
4411
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_lucide_react3.Plus, { className: cn(iconSize, "mr-2") }),
|
|
4412
|
+
"\u63D2\u5165\u8868\u683C (3x3)"
|
|
4413
|
+
]
|
|
4414
|
+
}
|
|
4415
|
+
),
|
|
4416
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(DropdownMenuSeparator, {}),
|
|
4417
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
4418
|
+
DropdownMenuItem,
|
|
4419
|
+
{
|
|
4420
|
+
onClick: () => editor.chain().focus().addColumnAfter().run(),
|
|
4421
|
+
disabled: !editor.can().addColumnAfter(),
|
|
4422
|
+
children: "\u65B0\u589E\u6B04"
|
|
4423
|
+
}
|
|
4424
|
+
),
|
|
4425
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
4426
|
+
DropdownMenuItem,
|
|
4427
|
+
{
|
|
4428
|
+
onClick: () => editor.chain().focus().addRowAfter().run(),
|
|
4429
|
+
disabled: !editor.can().addRowAfter(),
|
|
4430
|
+
children: "\u65B0\u589E\u5217"
|
|
4431
|
+
}
|
|
4432
|
+
),
|
|
4433
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(DropdownMenuSeparator, {}),
|
|
4434
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
4435
|
+
DropdownMenuItem,
|
|
4436
|
+
{
|
|
4437
|
+
onClick: () => editor.chain().focus().deleteColumn().run(),
|
|
4438
|
+
disabled: !editor.can().deleteColumn(),
|
|
4439
|
+
children: "\u522A\u9664\u6B04"
|
|
4440
|
+
}
|
|
4441
|
+
),
|
|
4442
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
4443
|
+
DropdownMenuItem,
|
|
4444
|
+
{
|
|
4445
|
+
onClick: () => editor.chain().focus().deleteRow().run(),
|
|
4446
|
+
disabled: !editor.can().deleteRow(),
|
|
4447
|
+
children: "\u522A\u9664\u5217"
|
|
4448
|
+
}
|
|
4449
|
+
),
|
|
4450
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(DropdownMenuSeparator, {}),
|
|
4451
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
4452
|
+
DropdownMenuItem,
|
|
4453
|
+
{
|
|
4454
|
+
onClick: () => editor.chain().focus().deleteTable().run(),
|
|
4455
|
+
disabled: !editor.can().deleteTable(),
|
|
4456
|
+
className: "text-destructive",
|
|
4457
|
+
children: [
|
|
4458
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_lucide_react3.Trash2, { className: cn(iconSize, "mr-2") }),
|
|
4459
|
+
"\u522A\u9664\u8868\u683C"
|
|
4460
|
+
]
|
|
4461
|
+
}
|
|
4462
|
+
)
|
|
4463
|
+
] })
|
|
4464
|
+
] });
|
|
4465
|
+
}
|
|
4466
|
+
|
|
4467
|
+
// src/components/CalloutDropdown.tsx
|
|
4468
|
+
var import_react = require("react");
|
|
4469
|
+
var import_lucide_react4 = require("lucide-react");
|
|
4470
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
4471
|
+
function CalloutDropdown({ editor, iconSize = "h-4 w-4" }) {
|
|
4472
|
+
const [open, setOpen] = (0, import_react.useState)(false);
|
|
4473
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(DropdownMenu, { open, onOpenChange: setOpen, modal: false, children: [
|
|
4474
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Button, { variant: "ghost", size: "sm", className: "h-8 px-2 gap-1", children: [
|
|
4475
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_lucide_react4.MessageSquare, { className: iconSize }),
|
|
4476
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_lucide_react4.ChevronDown, { className: "h-3 w-3" })
|
|
4477
|
+
] }) }),
|
|
4478
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(DropdownMenuContent, { align: "start", className: "min-w-0 p-1.5", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex gap-1", children: [
|
|
4479
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
4480
|
+
"button",
|
|
4481
|
+
{
|
|
4482
|
+
type: "button",
|
|
4483
|
+
className: "w-6 h-6 rounded bg-emerald-100 border border-emerald-300 hover:scale-110 transition-transform",
|
|
4484
|
+
onClick: () => {
|
|
4485
|
+
setOpen(false);
|
|
4486
|
+
setTimeout(() => {
|
|
4487
|
+
editor.chain().focus().setCallout({ type: "success" }).run();
|
|
4488
|
+
}, 0);
|
|
4489
|
+
},
|
|
4490
|
+
title: "\u6210\u529F\u63D0\u793A",
|
|
4491
|
+
"aria-label": "\u6210\u529F\u63D0\u793A"
|
|
4492
|
+
}
|
|
4493
|
+
),
|
|
4494
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
4495
|
+
"button",
|
|
4496
|
+
{
|
|
4497
|
+
type: "button",
|
|
4498
|
+
className: "w-6 h-6 rounded bg-amber-100 border border-amber-300 hover:scale-110 transition-transform",
|
|
4499
|
+
onClick: () => {
|
|
4500
|
+
setOpen(false);
|
|
4501
|
+
setTimeout(() => {
|
|
4502
|
+
editor.chain().focus().setCallout({ type: "warning" }).run();
|
|
4503
|
+
}, 0);
|
|
4504
|
+
},
|
|
4505
|
+
title: "\u8B66\u544A\u63D0\u793A",
|
|
4506
|
+
"aria-label": "\u8B66\u544A\u63D0\u793A"
|
|
4507
|
+
}
|
|
4508
|
+
),
|
|
4509
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
4510
|
+
"button",
|
|
4511
|
+
{
|
|
4512
|
+
type: "button",
|
|
4513
|
+
className: "w-6 h-6 rounded bg-red-100 border border-red-300 hover:scale-110 transition-transform",
|
|
4514
|
+
onClick: () => {
|
|
4515
|
+
setOpen(false);
|
|
4516
|
+
setTimeout(() => {
|
|
4517
|
+
editor.chain().focus().setCallout({ type: "error" }).run();
|
|
4518
|
+
}, 0);
|
|
4519
|
+
},
|
|
4520
|
+
title: "\u932F\u8AA4\u63D0\u793A",
|
|
4521
|
+
"aria-label": "\u932F\u8AA4\u63D0\u793A"
|
|
4522
|
+
}
|
|
4523
|
+
),
|
|
4524
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
4525
|
+
"button",
|
|
4526
|
+
{
|
|
4527
|
+
type: "button",
|
|
4528
|
+
className: "w-6 h-6 rounded bg-sky-100 border border-sky-300 hover:scale-110 transition-transform",
|
|
4529
|
+
onClick: () => {
|
|
4530
|
+
setOpen(false);
|
|
4531
|
+
setTimeout(() => {
|
|
4532
|
+
editor.chain().focus().setCallout({ type: "info" }).run();
|
|
4533
|
+
}, 0);
|
|
4534
|
+
},
|
|
4535
|
+
title: "\u8CC7\u8A0A\u63D0\u793A",
|
|
4536
|
+
"aria-label": "\u8CC7\u8A0A\u63D0\u793A"
|
|
4537
|
+
}
|
|
4538
|
+
)
|
|
4539
|
+
] }) })
|
|
4540
|
+
] });
|
|
4541
|
+
}
|
|
4542
|
+
|
|
4543
|
+
// src/components/ColorPicker.tsx
|
|
4544
|
+
var import_lucide_react5 = require("lucide-react");
|
|
4545
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
4546
|
+
var COLOR_PALETTE = [
|
|
4547
|
+
{ name: "\u9ED1\u8272", value: "#000000" },
|
|
4548
|
+
{ name: "\u7070\u8272", value: "#6B7280" },
|
|
4549
|
+
{ name: "\u7D05\u8272", value: "#EF4444" },
|
|
4550
|
+
{ name: "\u6A59\u8272", value: "#F97316" },
|
|
4551
|
+
{ name: "\u9EC3\u8272", value: "#EAB308" },
|
|
4552
|
+
{ name: "\u7DA0\u8272", value: "#22C55E" },
|
|
4553
|
+
{ name: "\u85CD\u8272", value: "#3B82F6" },
|
|
4554
|
+
{ name: "\u7D2B\u8272", value: "#8B5CF6" }
|
|
4555
|
+
];
|
|
4556
|
+
function ColorPicker({ editor, iconSize = "h-4 w-4" }) {
|
|
4557
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(DropdownMenu, { children: [
|
|
4558
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Button, { variant: "ghost", size: "sm", className: "h-8 px-2 gap-1", title: "\u984F\u8272", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react5.Palette, { className: iconSize }) }) }),
|
|
4559
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(DropdownMenuContent, { align: "start", className: "w-72", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "p-2", children: [
|
|
4560
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "text-xs font-medium text-muted-foreground mb-2", children: "\u6587\u5B57\u984F\u8272" }),
|
|
4561
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex gap-1.5 mb-3", children: [
|
|
4562
|
+
COLOR_PALETTE.map((color) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
4563
|
+
"button",
|
|
4564
|
+
{
|
|
4565
|
+
type: "button",
|
|
4566
|
+
className: "w-6 h-6 rounded border border-border dark:border-zinc-600 hover:scale-110 transition-transform",
|
|
4567
|
+
style: { backgroundColor: color.value },
|
|
4568
|
+
onClick: () => editor.chain().focus().setColor(color.value).run(),
|
|
4569
|
+
title: color.name,
|
|
4570
|
+
"aria-label": `\u6587\u5B57\u984F\u8272\uFF1A${color.name}`
|
|
4571
|
+
},
|
|
4572
|
+
`text-${color.value}`
|
|
4573
|
+
)),
|
|
4574
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
4575
|
+
"button",
|
|
4576
|
+
{
|
|
4577
|
+
type: "button",
|
|
4578
|
+
className: "w-6 h-6 rounded border border-border dark:border-zinc-600 hover:scale-110 transition-transform flex items-center justify-center bg-background",
|
|
4579
|
+
onClick: () => editor.chain().focus().unsetColor().run(),
|
|
4580
|
+
title: "\u6E05\u9664\u6587\u5B57\u984F\u8272",
|
|
4581
|
+
"aria-label": "\u6E05\u9664\u6587\u5B57\u984F\u8272",
|
|
4582
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react5.X, { className: "h-3 w-3" })
|
|
4583
|
+
}
|
|
4584
|
+
)
|
|
4585
|
+
] }),
|
|
4586
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(DropdownMenuSeparator, {}),
|
|
4587
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "text-xs font-medium text-muted-foreground mb-2 mt-2", children: "\u80CC\u666F\u8272" }),
|
|
4588
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex gap-1.5", children: [
|
|
4589
|
+
COLOR_PALETTE.map((color) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
4590
|
+
"button",
|
|
4591
|
+
{
|
|
4592
|
+
type: "button",
|
|
4593
|
+
className: "w-6 h-6 rounded border border-border dark:border-zinc-600 hover:scale-110 transition-transform",
|
|
4594
|
+
style: { backgroundColor: color.value },
|
|
4595
|
+
onClick: () => editor.chain().focus().toggleHighlight({ color: color.value }).run(),
|
|
4596
|
+
title: color.name,
|
|
4597
|
+
"aria-label": `\u80CC\u666F\u8272\uFF1A${color.name}`
|
|
4598
|
+
},
|
|
4599
|
+
`bg-${color.value}`
|
|
4600
|
+
)),
|
|
4601
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
4602
|
+
"button",
|
|
4603
|
+
{
|
|
4604
|
+
type: "button",
|
|
4605
|
+
className: "w-6 h-6 rounded border border-border dark:border-zinc-600 hover:scale-110 transition-transform flex items-center justify-center bg-background",
|
|
4606
|
+
onClick: () => editor.chain().focus().unsetHighlight().run(),
|
|
4607
|
+
title: "\u6E05\u9664\u80CC\u666F\u8272",
|
|
4608
|
+
"aria-label": "\u6E05\u9664\u80CC\u666F\u8272",
|
|
4609
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react5.X, { className: "h-3 w-3" })
|
|
4610
|
+
}
|
|
4611
|
+
)
|
|
4612
|
+
] })
|
|
4613
|
+
] }) })
|
|
4614
|
+
] });
|
|
4615
|
+
}
|
|
4616
|
+
|
|
4617
|
+
// src/components/Toolbar.tsx
|
|
4618
|
+
var import_lucide_react6 = require("lucide-react");
|
|
4619
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
4620
|
+
var ICON_SIZE = "h-4 w-4";
|
|
4621
|
+
var TEXT_FORMAT_BUTTONS = [
|
|
4622
|
+
{ key: "bold", icon: import_lucide_react6.Bold, title: "\u7C97\u9AD4", isActive: (e) => e.isActive("bold"), action: (e) => e.chain().focus().toggleBold().run() },
|
|
4623
|
+
{ key: "italic", icon: import_lucide_react6.Italic, title: "\u659C\u9AD4", isActive: (e) => e.isActive("italic"), action: (e) => e.chain().focus().toggleItalic().run() },
|
|
4624
|
+
{ key: "code", icon: import_lucide_react6.Code, title: "\u884C\u5167\u7A0B\u5F0F\u78BC", isActive: (e) => e.isActive("code"), action: (e) => e.chain().focus().toggleCode().run() },
|
|
4625
|
+
{ key: "underline", icon: import_lucide_react6.Underline, title: "\u5E95\u7DDA", isActive: (e) => e.isActive("underline"), action: (e) => e.chain().focus().toggleUnderline().run() }
|
|
4626
|
+
];
|
|
4627
|
+
var SCRIPT_BUTTONS = [
|
|
4628
|
+
{ key: "superscript", icon: import_lucide_react6.Superscript, title: "\u4E0A\u6A19", isActive: (e) => e.isActive("superscript"), action: (e) => e.chain().focus().toggleSuperscript().run() },
|
|
4629
|
+
{ key: "subscript", icon: import_lucide_react6.Subscript, title: "\u4E0B\u6A19", isActive: (e) => e.isActive("subscript"), action: (e) => e.chain().focus().toggleSubscript().run() }
|
|
4630
|
+
];
|
|
4631
|
+
var ALIGN_BUTTONS = [
|
|
4632
|
+
{ key: "left", icon: import_lucide_react6.AlignLeft, title: "\u9760\u5DE6\u5C0D\u9F4A", isActive: (e) => e.isActive({ textAlign: "left" }), action: (e) => e.chain().focus().setTextAlign("left").run() },
|
|
4633
|
+
{ key: "center", icon: import_lucide_react6.AlignCenter, title: "\u7F6E\u4E2D\u5C0D\u9F4A", isActive: (e) => e.isActive({ textAlign: "center" }), action: (e) => e.chain().focus().setTextAlign("center").run() },
|
|
4634
|
+
{ key: "right", icon: import_lucide_react6.AlignRight, title: "\u9760\u53F3\u5C0D\u9F4A", isActive: (e) => e.isActive({ textAlign: "right" }), action: (e) => e.chain().focus().setTextAlign("right").run() }
|
|
4635
|
+
];
|
|
4636
|
+
function ToolbarButtonGroup({ buttons, editor }) {
|
|
4637
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_jsx_runtime11.Fragment, { children: buttons.map(({ key, icon: Icon, title, isActive, action }) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
4638
|
+
ToolbarButton,
|
|
4639
|
+
{
|
|
4640
|
+
pressed: isActive(editor),
|
|
4641
|
+
onPressedChange: () => action(editor),
|
|
4642
|
+
title,
|
|
4643
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Icon, { className: ICON_SIZE })
|
|
4644
|
+
},
|
|
4645
|
+
key
|
|
4646
|
+
)) });
|
|
4647
|
+
}
|
|
4648
|
+
function normalizeConfig(config) {
|
|
4649
|
+
if (config === "none") return [];
|
|
4650
|
+
if (config === "all" || !config) {
|
|
4651
|
+
return [
|
|
4652
|
+
["heading", "list", "table", "callout"],
|
|
4653
|
+
["format", "link", "color"],
|
|
4654
|
+
["script"],
|
|
4655
|
+
["align"],
|
|
4656
|
+
["image"],
|
|
4657
|
+
["themeToggle"]
|
|
4658
|
+
];
|
|
4659
|
+
}
|
|
4660
|
+
if (Array.isArray(config)) {
|
|
4661
|
+
if (config.length > 0 && Array.isArray(config[0])) {
|
|
4662
|
+
return config;
|
|
4663
|
+
}
|
|
4664
|
+
return [config];
|
|
4665
|
+
}
|
|
4666
|
+
return [];
|
|
4667
|
+
}
|
|
4668
|
+
function Toolbar({
|
|
4669
|
+
editor,
|
|
4670
|
+
config,
|
|
4671
|
+
toolbarStart,
|
|
4672
|
+
toolbarEnd,
|
|
4673
|
+
theme,
|
|
4674
|
+
onThemeToggle,
|
|
4675
|
+
onImageUpload
|
|
4676
|
+
}) {
|
|
4677
|
+
const fileInputRef = (0, import_react2.useRef)(null);
|
|
4678
|
+
if (!editor) return null;
|
|
4679
|
+
const groups = normalizeConfig(config);
|
|
4680
|
+
const setLink = () => {
|
|
4681
|
+
const previousUrl = editor.getAttributes("link").href;
|
|
4682
|
+
const url = window.prompt("\u8F38\u5165\u9023\u7D50\u7DB2\u5740", previousUrl);
|
|
4683
|
+
if (url === null) return;
|
|
4684
|
+
if (url === "") {
|
|
4685
|
+
editor.chain().focus().extendMarkRange("link").unsetLink().run();
|
|
4686
|
+
return;
|
|
4687
|
+
}
|
|
4688
|
+
editor.chain().focus().extendMarkRange("link").setLink({ href: url }).run();
|
|
4689
|
+
};
|
|
4690
|
+
const handleImageUpload = (e) => {
|
|
4691
|
+
const file = e.target.files?.[0];
|
|
4692
|
+
if (!file) return;
|
|
4693
|
+
const MAX_SIZE = 5 * 1024 * 1024;
|
|
4694
|
+
if (file.size > MAX_SIZE) {
|
|
4695
|
+
alert("\u5716\u7247\u5927\u5C0F\u4E0D\u53EF\u8D85\u904E 5MB");
|
|
4696
|
+
e.target.value = "";
|
|
4697
|
+
return;
|
|
4698
|
+
}
|
|
4699
|
+
if (onImageUpload) {
|
|
4700
|
+
onImageUpload(file);
|
|
4701
|
+
} else {
|
|
4702
|
+
const reader = new FileReader();
|
|
4703
|
+
reader.onload = () => {
|
|
4704
|
+
const base64 = reader.result;
|
|
4705
|
+
editor.chain().focus().setImage({ src: base64 }).run();
|
|
4706
|
+
};
|
|
4707
|
+
reader.onerror = () => {
|
|
4708
|
+
console.error("\u5716\u7247\u8B80\u53D6\u5931\u6557");
|
|
4709
|
+
};
|
|
4710
|
+
reader.readAsDataURL(file);
|
|
4711
|
+
}
|
|
4712
|
+
e.target.value = "";
|
|
4713
|
+
};
|
|
4714
|
+
const renderToolbarItem = (item) => {
|
|
4715
|
+
switch (item) {
|
|
4716
|
+
case "heading":
|
|
4717
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(HeadingDropdown, { editor, iconSize: ICON_SIZE }, "heading");
|
|
4718
|
+
case "list":
|
|
4719
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(ListDropdown, { editor, iconSize: ICON_SIZE }, "list");
|
|
4720
|
+
case "table":
|
|
4721
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(TableDropdown, { editor, iconSize: ICON_SIZE }, "table");
|
|
4722
|
+
case "callout":
|
|
4723
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(CalloutDropdown, { editor, iconSize: ICON_SIZE }, "callout");
|
|
4724
|
+
case "format":
|
|
4725
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(ToolbarButtonGroup, { buttons: TEXT_FORMAT_BUTTONS, editor }, "format");
|
|
4726
|
+
case "link":
|
|
4727
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
4728
|
+
ToolbarButton,
|
|
4729
|
+
{
|
|
4730
|
+
pressed: editor.isActive("link"),
|
|
4731
|
+
onPressedChange: setLink,
|
|
4732
|
+
title: "\u9023\u7D50",
|
|
4733
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_lucide_react6.Link, { className: ICON_SIZE })
|
|
4734
|
+
},
|
|
4735
|
+
"link"
|
|
4736
|
+
);
|
|
4737
|
+
case "color":
|
|
4738
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(ColorPicker, { editor, iconSize: ICON_SIZE }, "color");
|
|
4739
|
+
case "script":
|
|
4740
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(ToolbarButtonGroup, { buttons: SCRIPT_BUTTONS, editor }, "script");
|
|
4741
|
+
case "align":
|
|
4742
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(ToolbarButtonGroup, { buttons: ALIGN_BUTTONS, editor }, "align");
|
|
4743
|
+
case "image":
|
|
4744
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
4745
|
+
Button,
|
|
4746
|
+
{
|
|
4747
|
+
variant: "ghost",
|
|
4748
|
+
size: "sm",
|
|
4749
|
+
className: "h-8 px-2 gap-1",
|
|
4750
|
+
onClick: () => fileInputRef.current?.click(),
|
|
4751
|
+
title: "\u63D2\u5165\u5716\u7247",
|
|
4752
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_lucide_react6.ImagePlus, { className: ICON_SIZE })
|
|
4753
|
+
},
|
|
4754
|
+
"image"
|
|
4755
|
+
);
|
|
4756
|
+
case "themeToggle":
|
|
4757
|
+
return onThemeToggle ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
4758
|
+
Button,
|
|
4759
|
+
{
|
|
4760
|
+
variant: "ghost",
|
|
4761
|
+
size: "sm",
|
|
4762
|
+
className: "h-8 w-8 p-0",
|
|
4763
|
+
onClick: onThemeToggle,
|
|
4764
|
+
title: theme === "dark" ? "\u5207\u63DB\u6DFA\u8272\u6A21\u5F0F" : "\u5207\u63DB\u6DF1\u8272\u6A21\u5F0F",
|
|
4765
|
+
children: theme === "dark" ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_lucide_react6.Moon, { className: ICON_SIZE }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_lucide_react6.Sun, { className: ICON_SIZE })
|
|
4766
|
+
},
|
|
4767
|
+
"themeToggle"
|
|
4768
|
+
) : null;
|
|
4769
|
+
default:
|
|
4770
|
+
return null;
|
|
4771
|
+
}
|
|
4772
|
+
};
|
|
4773
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "flex items-center justify-center mb-2 relative", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex items-center justify-between px-2 py-1.5 bg-white dark:bg-zinc-900 rounded-lg shadow-sm w-full max-w-7xl mx-auto", children: [
|
|
4774
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex items-center gap-0.5", children: [
|
|
4775
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
4776
|
+
"input",
|
|
4777
|
+
{
|
|
4778
|
+
ref: fileInputRef,
|
|
4779
|
+
type: "file",
|
|
4780
|
+
accept: "image/*",
|
|
4781
|
+
className: "hidden",
|
|
4782
|
+
onChange: handleImageUpload,
|
|
4783
|
+
"aria-label": "\u4E0A\u50B3\u5716\u7247"
|
|
4784
|
+
}
|
|
4785
|
+
),
|
|
4786
|
+
toolbarStart,
|
|
4787
|
+
groups.map((group, groupIndex) => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex items-center gap-0.5", children: [
|
|
4788
|
+
groupIndex > 0 && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(ToolbarDivider, {}),
|
|
4789
|
+
group.map((item) => renderToolbarItem(item))
|
|
4790
|
+
] }, groupIndex))
|
|
4791
|
+
] }),
|
|
4792
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "flex items-center gap-0.5", children: toolbarEnd })
|
|
4793
|
+
] }) });
|
|
4794
|
+
}
|
|
4795
|
+
|
|
4796
|
+
// src/EliaEditor.tsx
|
|
4797
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
4798
|
+
function EliaEditor({
|
|
4799
|
+
content = "",
|
|
4800
|
+
onChange,
|
|
4801
|
+
placeholder = "\u958B\u59CB\u5BEB\u4F5C...",
|
|
4802
|
+
toolbar = "all",
|
|
4803
|
+
header,
|
|
4804
|
+
toolbarStart,
|
|
4805
|
+
toolbarEnd,
|
|
4806
|
+
footer,
|
|
4807
|
+
className,
|
|
4808
|
+
editorClassName,
|
|
4809
|
+
autofocus = false,
|
|
4810
|
+
readOnly = false,
|
|
4811
|
+
theme,
|
|
4812
|
+
onThemeToggle,
|
|
4813
|
+
onImageUpload
|
|
4814
|
+
}) {
|
|
4815
|
+
const isInternalUpdate = (0, import_react3.useRef)(false);
|
|
4816
|
+
const handleUpdate = (0, import_react3.useCallback)(
|
|
4817
|
+
({ editor: editor2 }) => {
|
|
4818
|
+
isInternalUpdate.current = true;
|
|
4819
|
+
onChange?.(editor2.getHTML());
|
|
4820
|
+
},
|
|
4821
|
+
[onChange]
|
|
4822
|
+
);
|
|
4823
|
+
const editor = (0, import_react4.useEditor)({
|
|
4824
|
+
extensions: [
|
|
4825
|
+
import_starter_kit.default.configure({
|
|
4826
|
+
heading: {
|
|
4827
|
+
levels: [1, 2, 3]
|
|
4828
|
+
}
|
|
4829
|
+
}),
|
|
4830
|
+
import_extension_placeholder.default.configure({
|
|
4831
|
+
placeholder
|
|
4832
|
+
}),
|
|
4833
|
+
import_extension_underline.default,
|
|
4834
|
+
import_extension_text_align.default.configure({
|
|
4835
|
+
types: ["heading", "paragraph"]
|
|
4836
|
+
}),
|
|
4837
|
+
import_extension_link.default.configure({
|
|
4838
|
+
openOnClick: false,
|
|
4839
|
+
HTMLAttributes: {
|
|
4840
|
+
class: "text-primary underline underline-offset-4"
|
|
4841
|
+
}
|
|
4842
|
+
}),
|
|
4843
|
+
import_extension_text_style.TextStyle,
|
|
4844
|
+
import_extension_color.Color,
|
|
4845
|
+
import_extension_highlight.Highlight.configure({
|
|
4846
|
+
multicolor: true
|
|
4847
|
+
}),
|
|
4848
|
+
import_extension_subscript.default,
|
|
4849
|
+
import_extension_superscript.default,
|
|
4850
|
+
import_extension_task_list.default,
|
|
4851
|
+
import_extension_task_item.default.configure({
|
|
4852
|
+
nested: true
|
|
4853
|
+
}),
|
|
4854
|
+
import_extension_table.Table.configure({
|
|
4855
|
+
resizable: true
|
|
4856
|
+
}),
|
|
4857
|
+
import_extension_table_row.TableRow,
|
|
4858
|
+
import_extension_table_header.TableHeader,
|
|
4859
|
+
import_extension_table_cell.TableCell,
|
|
4860
|
+
import_tiptap_extension_resize_image.default.configure({
|
|
4861
|
+
allowBase64: true
|
|
4862
|
+
}),
|
|
4863
|
+
Callout
|
|
4864
|
+
],
|
|
4865
|
+
content,
|
|
4866
|
+
autofocus,
|
|
4867
|
+
editable: !readOnly,
|
|
4868
|
+
editorProps: {
|
|
4869
|
+
attributes: {
|
|
4870
|
+
class: cn(
|
|
4871
|
+
"tiptap-editor min-h-[300px] p-4 focus:outline-none",
|
|
4872
|
+
editorClassName
|
|
4873
|
+
)
|
|
4874
|
+
}
|
|
4875
|
+
},
|
|
4876
|
+
onUpdate: handleUpdate
|
|
4877
|
+
});
|
|
4878
|
+
(0, import_react3.useEffect)(() => {
|
|
4879
|
+
if (editor && !isInternalUpdate.current && content !== editor.getHTML()) {
|
|
4880
|
+
editor.commands.setContent(content);
|
|
4881
|
+
}
|
|
4882
|
+
isInternalUpdate.current = false;
|
|
4883
|
+
}, [content, editor]);
|
|
4884
|
+
(0, import_react3.useEffect)(() => {
|
|
4885
|
+
if (editor) {
|
|
4886
|
+
editor.setEditable(!readOnly);
|
|
4887
|
+
}
|
|
4888
|
+
}, [readOnly, editor]);
|
|
4889
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: cn("elia-editor", className), children: [
|
|
4890
|
+
header && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "elia-editor-header", children: header }),
|
|
4891
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
4892
|
+
Toolbar,
|
|
4893
|
+
{
|
|
4894
|
+
editor,
|
|
4895
|
+
config: toolbar,
|
|
4896
|
+
toolbarStart,
|
|
4897
|
+
toolbarEnd,
|
|
4898
|
+
theme,
|
|
4899
|
+
onThemeToggle,
|
|
4900
|
+
onImageUpload
|
|
4901
|
+
}
|
|
4902
|
+
),
|
|
4903
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react4.EditorContent, { editor }),
|
|
4904
|
+
footer && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "elia-editor-footer", children: footer })
|
|
4905
|
+
] });
|
|
4906
|
+
}
|
|
4907
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
4908
|
+
0 && (module.exports = {
|
|
4909
|
+
Button,
|
|
4910
|
+
Callout,
|
|
4911
|
+
CalloutDropdown,
|
|
4912
|
+
ColorPicker,
|
|
4913
|
+
DropdownMenu,
|
|
4914
|
+
DropdownMenuContent,
|
|
4915
|
+
DropdownMenuItem,
|
|
4916
|
+
DropdownMenuSeparator,
|
|
4917
|
+
DropdownMenuTrigger,
|
|
4918
|
+
EliaEditor,
|
|
4919
|
+
HeadingDropdown,
|
|
4920
|
+
ListDropdown,
|
|
4921
|
+
TableDropdown,
|
|
4922
|
+
Toggle,
|
|
4923
|
+
Toolbar,
|
|
4924
|
+
ToolbarButton,
|
|
4925
|
+
ToolbarDivider,
|
|
4926
|
+
cn
|
|
4927
|
+
});
|
|
4928
|
+
//# sourceMappingURL=index.cjs.map
|