dn-react-text-editor 0.2.4 → 0.3.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/create_text_editor.d.mts +9 -19
- package/dist/create_text_editor.d.ts +9 -19
- package/dist/create_text_editor.js +432 -448
- package/dist/create_text_editor.mjs +433 -449
- package/dist/html.js +1 -1
- package/dist/html.mjs +1 -1
- package/dist/index.d.mts +5 -6
- package/dist/index.d.ts +5 -6
- package/dist/index.js +435 -449
- package/dist/index.mjs +435 -450
- package/dist/input.d.mts +6 -8
- package/dist/input.d.ts +6 -8
- package/dist/input.js +1 -6
- package/dist/input.mjs +1 -6
- package/dist/text_editor_controller.d.mts +29 -16
- package/dist/text_editor_controller.d.ts +29 -16
- package/dist/text_editor_controller.js +604 -107
- package/dist/text_editor_controller.mjs +602 -105
- package/package.json +55 -55
|
@@ -34,13 +34,231 @@ __export(create_text_editor_exports, {
|
|
|
34
34
|
});
|
|
35
35
|
module.exports = __toCommonJS(create_text_editor_exports);
|
|
36
36
|
var import_react2 = __toESM(require("react"));
|
|
37
|
-
var import_prosemirror_state6 = require("prosemirror-state");
|
|
38
|
-
var import_prosemirror_view5 = require("prosemirror-view");
|
|
39
37
|
var import_react3 = require("react");
|
|
40
38
|
|
|
41
|
-
// src/
|
|
39
|
+
// src/input.tsx
|
|
40
|
+
var import_react = __toESM(require("react"));
|
|
41
|
+
var import_rxjs = require("rxjs");
|
|
42
|
+
function TextEditorInput({
|
|
43
|
+
controller,
|
|
44
|
+
onChange,
|
|
45
|
+
updateDelay = 0,
|
|
46
|
+
...props
|
|
47
|
+
}) {
|
|
48
|
+
const inputRef = import_react.default.useRef(null);
|
|
49
|
+
(0, import_react.useEffect)(() => {
|
|
50
|
+
const sub = controller.subject.pipe(
|
|
51
|
+
(0, import_rxjs.filter)((tr) => tr.docChanged),
|
|
52
|
+
(0, import_rxjs.debounceTime)(updateDelay)
|
|
53
|
+
).subscribe(() => {
|
|
54
|
+
if (inputRef.current) {
|
|
55
|
+
inputRef.current.value = controller.value;
|
|
56
|
+
const event = new Event("input", { bubbles: true });
|
|
57
|
+
inputRef.current.dispatchEvent(event);
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
return () => {
|
|
61
|
+
sub.unsubscribe();
|
|
62
|
+
};
|
|
63
|
+
}, []);
|
|
64
|
+
return /* @__PURE__ */ import_react.default.createElement("input", { ...props, ref: inputRef, type: "hidden", onInput: onChange });
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// src/text_editor_controller.tsx
|
|
68
|
+
var import_prosemirror_state5 = require("prosemirror-state");
|
|
69
|
+
var import_prosemirror_view4 = require("prosemirror-view");
|
|
70
|
+
var commands2 = __toESM(require("prosemirror-commands"));
|
|
71
|
+
var import_prosemirror_keymap = require("prosemirror-keymap");
|
|
72
|
+
|
|
73
|
+
// src/plugins/drag_and_drop.tsx
|
|
74
|
+
var import_prosemirror_state = require("prosemirror-state");
|
|
75
|
+
function dragAndDropPlugin({ attachFile }) {
|
|
76
|
+
return new import_prosemirror_state.Plugin({
|
|
77
|
+
props: {
|
|
78
|
+
handleDOMEvents: {
|
|
79
|
+
drop(view, event) {
|
|
80
|
+
if (!attachFile) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
const files = event.dataTransfer?.files;
|
|
84
|
+
if (!files || files.length === 0) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
event.preventDefault();
|
|
88
|
+
const pos = view.state.selection.$from.pos || view.posAtCoords({
|
|
89
|
+
left: event.clientX,
|
|
90
|
+
top: event.clientY
|
|
91
|
+
})?.pos || null;
|
|
92
|
+
if (pos === null) {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
const medias = Array.from(files).filter(
|
|
96
|
+
(file) => file.type.startsWith("image/") || file.type.startsWith("video/")
|
|
97
|
+
);
|
|
98
|
+
attachFile(view, medias);
|
|
99
|
+
return true;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// src/plugins/upload_placeholder.tsx
|
|
107
|
+
var import_prosemirror_state2 = require("prosemirror-state");
|
|
108
|
+
var import_prosemirror_view = require("prosemirror-view");
|
|
109
|
+
var uploadPlaceholderPlugin = new import_prosemirror_state2.Plugin({
|
|
110
|
+
state: {
|
|
111
|
+
init() {
|
|
112
|
+
return import_prosemirror_view.DecorationSet.empty;
|
|
113
|
+
},
|
|
114
|
+
apply(tr, set) {
|
|
115
|
+
set = set.map(tr.mapping, tr.doc);
|
|
116
|
+
const action = tr.getMeta(this);
|
|
117
|
+
if (action && action.add) {
|
|
118
|
+
const { type, width, height } = action.add;
|
|
119
|
+
const widget = document.createElement("div");
|
|
120
|
+
widget.className = "upload-placeholder";
|
|
121
|
+
widget.style.width = `100%`;
|
|
122
|
+
if (type.startsWith("image/") || type.startsWith("video/")) {
|
|
123
|
+
widget.style.aspectRatio = `${width} / ${height}`;
|
|
124
|
+
widget.style.maxWidth = `${width}px`;
|
|
125
|
+
} else {
|
|
126
|
+
widget.style.height = "80px";
|
|
127
|
+
}
|
|
128
|
+
const progress = document.createElement("div");
|
|
129
|
+
progress.className = "upload-progress";
|
|
130
|
+
widget.appendChild(progress);
|
|
131
|
+
const deco = import_prosemirror_view.Decoration.widget(action.add.pos, widget, {
|
|
132
|
+
id: action.add.id
|
|
133
|
+
});
|
|
134
|
+
set = set.add(tr.doc, [deco]);
|
|
135
|
+
} else if (action && action.progress) {
|
|
136
|
+
const found = set.find(
|
|
137
|
+
void 0,
|
|
138
|
+
void 0,
|
|
139
|
+
(spec) => spec.id === action.progress.id
|
|
140
|
+
);
|
|
141
|
+
if (found.length) {
|
|
142
|
+
const widget = found[0].type.toDOM;
|
|
143
|
+
const progress = widget.querySelector(".upload-progress");
|
|
144
|
+
if (progress) {
|
|
145
|
+
progress.innerHTML = `${Math.round(action.progress.progress)}%`;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
} else if (action && action.remove) {
|
|
149
|
+
set = set.remove(
|
|
150
|
+
set.find(void 0, void 0, (spec) => spec.id === action.remove.id)
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
return set;
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
props: {
|
|
157
|
+
decorations(state) {
|
|
158
|
+
return this.getState(state);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
var findPlaceholder = (state, id) => {
|
|
163
|
+
const decos = uploadPlaceholderPlugin.getState(state);
|
|
164
|
+
if (!decos) {
|
|
165
|
+
return null;
|
|
166
|
+
}
|
|
167
|
+
const found = decos.find(void 0, void 0, (spec) => spec.id === id);
|
|
168
|
+
return found.length ? found[0].from : null;
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
// src/plugins/placehoder.tsx
|
|
42
172
|
var import_prosemirror_model = require("prosemirror-model");
|
|
173
|
+
var import_prosemirror_state3 = require("prosemirror-state");
|
|
174
|
+
var import_prosemirror_view2 = require("prosemirror-view");
|
|
175
|
+
var getFirstChildDescendants = (view) => {
|
|
176
|
+
const nodes = [];
|
|
177
|
+
view.state.doc?.descendants((n) => {
|
|
178
|
+
nodes.push(n);
|
|
179
|
+
});
|
|
180
|
+
return nodes;
|
|
181
|
+
};
|
|
182
|
+
function placeholderPlugin(text) {
|
|
183
|
+
const update = (view) => {
|
|
184
|
+
const decos = uploadPlaceholderPlugin.getState(view.state);
|
|
185
|
+
if (decos && decos.find().length > 0 || view.state.doc.content.content.some((e) => e.type.name !== "paragraph") || view.state.doc.childCount > 1 || getFirstChildDescendants(view).length > 1 || view.state.doc.textContent) {
|
|
186
|
+
view.dom.removeAttribute("data-placeholder");
|
|
187
|
+
} else {
|
|
188
|
+
view.dom.setAttribute("data-placeholder", text);
|
|
189
|
+
}
|
|
190
|
+
};
|
|
191
|
+
return new import_prosemirror_state3.Plugin({
|
|
192
|
+
view(view) {
|
|
193
|
+
update(view);
|
|
194
|
+
return { update };
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// src/text_editor_controller.tsx
|
|
200
|
+
var import_prosemirror_history2 = require("prosemirror-history");
|
|
201
|
+
|
|
202
|
+
// src/plugins/keymap.tsx
|
|
203
|
+
var import_prosemirror_state4 = require("prosemirror-state");
|
|
204
|
+
var import_prosemirror_history = require("prosemirror-history");
|
|
205
|
+
var import_prosemirror_commands = require("prosemirror-commands");
|
|
43
206
|
var import_prosemirror_schema_list = require("prosemirror-schema-list");
|
|
207
|
+
function buildKeymap(schema) {
|
|
208
|
+
const keys = {};
|
|
209
|
+
function bind(key, cmd) {
|
|
210
|
+
keys[key] = cmd;
|
|
211
|
+
}
|
|
212
|
+
bind("Mod-z", import_prosemirror_history.undo);
|
|
213
|
+
bind("Shift-Mod-z", import_prosemirror_history.redo);
|
|
214
|
+
bind("Mod-y", import_prosemirror_history.redo);
|
|
215
|
+
const li = schema.nodes.list_item;
|
|
216
|
+
bind(
|
|
217
|
+
"Enter",
|
|
218
|
+
(0, import_prosemirror_commands.chainCommands)((0, import_prosemirror_schema_list.splitListItem)(li), (state, dispatch) => {
|
|
219
|
+
const { $head } = state.selection;
|
|
220
|
+
if ($head.parent.type === state.schema.nodes.paragraph) {
|
|
221
|
+
(0, import_prosemirror_commands.splitBlockAs)((n) => {
|
|
222
|
+
return {
|
|
223
|
+
type: n.type,
|
|
224
|
+
attrs: n.attrs
|
|
225
|
+
};
|
|
226
|
+
})(state, dispatch);
|
|
227
|
+
return true;
|
|
228
|
+
}
|
|
229
|
+
return false;
|
|
230
|
+
})
|
|
231
|
+
);
|
|
232
|
+
bind("ArrowDown", (state, dispatch) => {
|
|
233
|
+
const doc = state.doc;
|
|
234
|
+
const lastNode = doc.lastChild;
|
|
235
|
+
if (lastNode && lastNode.type.name !== "paragraph") {
|
|
236
|
+
const paragraphType = state.schema.nodes.paragraph;
|
|
237
|
+
let tr = state.tr;
|
|
238
|
+
const endPos = doc.content.size;
|
|
239
|
+
tr = tr.insert(endPos, paragraphType.create());
|
|
240
|
+
tr = tr.setSelection(import_prosemirror_state4.TextSelection.create(tr.doc, tr.doc.content.size));
|
|
241
|
+
if (dispatch) {
|
|
242
|
+
dispatch(tr);
|
|
243
|
+
}
|
|
244
|
+
return true;
|
|
245
|
+
}
|
|
246
|
+
return false;
|
|
247
|
+
});
|
|
248
|
+
return keys;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// src/cn.ts
|
|
252
|
+
function cn(...classes) {
|
|
253
|
+
return classes.filter(Boolean).join(" ").trim();
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// src/attach_file.tsx
|
|
257
|
+
var import_prosemirror_view3 = require("prosemirror-view");
|
|
258
|
+
|
|
259
|
+
// src/schema.tsx
|
|
260
|
+
var import_prosemirror_model2 = require("prosemirror-model");
|
|
261
|
+
var import_prosemirror_schema_list2 = require("prosemirror-schema-list");
|
|
44
262
|
|
|
45
263
|
// src/plugins/highlighter.ts
|
|
46
264
|
var import_highlight = __toESM(require("highlight.js"));
|
|
@@ -110,7 +328,7 @@ var highlighter = import_highlight.default;
|
|
|
110
328
|
|
|
111
329
|
// src/schema.tsx
|
|
112
330
|
function createSchema(spec = { nodes: {}, marks: {} }) {
|
|
113
|
-
const customSchema = new
|
|
331
|
+
const customSchema = new import_prosemirror_model2.Schema({
|
|
114
332
|
nodes: {
|
|
115
333
|
doc: { content: "block+" },
|
|
116
334
|
paragraph: {
|
|
@@ -521,320 +739,19 @@ function createSchema(spec = { nodes: {}, marks: {} }) {
|
|
|
521
739
|
},
|
|
522
740
|
topNode: spec.topNode
|
|
523
741
|
});
|
|
524
|
-
const prosemirrorSchema = new
|
|
525
|
-
nodes: (0,
|
|
742
|
+
const prosemirrorSchema = new import_prosemirror_model2.Schema({
|
|
743
|
+
nodes: (0, import_prosemirror_schema_list2.addListNodes)(customSchema.spec.nodes, "paragraph block*", "block"),
|
|
526
744
|
marks: customSchema.spec.marks
|
|
527
745
|
});
|
|
528
746
|
return prosemirrorSchema;
|
|
529
747
|
}
|
|
530
748
|
|
|
531
|
-
// src/
|
|
532
|
-
var
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
var createCommands = (schema, view, options = {}) => {
|
|
538
|
-
{
|
|
539
|
-
const isBlockTypeActive = (node, attrs, excludes = []) => {
|
|
540
|
-
const state = view.state;
|
|
541
|
-
const ranges = state.selection.ranges;
|
|
542
|
-
let active = false;
|
|
543
|
-
for (const range of ranges) {
|
|
544
|
-
const { $from, $to } = range;
|
|
545
|
-
state.doc.nodesBetween($from.pos, $to.pos, (n) => {
|
|
546
|
-
if (active) {
|
|
547
|
-
return true;
|
|
548
|
-
}
|
|
549
|
-
if (n.type !== node || excludes.includes(n.type)) {
|
|
550
|
-
return;
|
|
551
|
-
}
|
|
552
|
-
if (!attrs || Object.keys(attrs).every((key) => n.attrs[key] === attrs[key])) {
|
|
553
|
-
active = true;
|
|
554
|
-
}
|
|
555
|
-
});
|
|
556
|
-
return active;
|
|
557
|
-
}
|
|
558
|
-
};
|
|
559
|
-
const setBlockType2 = (node, attrs) => {
|
|
560
|
-
view.focus();
|
|
561
|
-
const nodeType = schema.nodes[node];
|
|
562
|
-
const command = commands.setBlockType(nodeType, attrs);
|
|
563
|
-
command(view.state, view.dispatch);
|
|
564
|
-
};
|
|
565
|
-
const toggleBlockType = (node, attrs) => {
|
|
566
|
-
view.focus();
|
|
567
|
-
const nodeType = schema.nodes[node];
|
|
568
|
-
const command = commands.setBlockType(nodeType, attrs);
|
|
569
|
-
if (isBlockTypeActive(nodeType, attrs)) {
|
|
570
|
-
command(view.state, view.dispatch);
|
|
571
|
-
}
|
|
572
|
-
};
|
|
573
|
-
const toggleMark2 = (mark, attrs, options2) => {
|
|
574
|
-
view.focus();
|
|
575
|
-
const markType = schema.marks[mark];
|
|
576
|
-
const command = commands.toggleMark(markType, attrs, options2);
|
|
577
|
-
command(view.state, view.dispatch);
|
|
578
|
-
};
|
|
579
|
-
const wrapInList2 = (listType, attrs) => {
|
|
580
|
-
view.focus();
|
|
581
|
-
const nodeType = schema.nodes[listType];
|
|
582
|
-
const command = schemaList.wrapInList(nodeType, attrs);
|
|
583
|
-
command(view.state, view.dispatch);
|
|
584
|
-
};
|
|
585
|
-
const clear = () => {
|
|
586
|
-
const tr = view.state.tr.replaceWith(
|
|
587
|
-
0,
|
|
588
|
-
view.state.doc.content.size,
|
|
589
|
-
schema.nodes.doc.createAndFill()
|
|
590
|
-
);
|
|
591
|
-
view.dispatch(tr);
|
|
592
|
-
};
|
|
593
|
-
return {
|
|
594
|
-
isBlockTypeActive,
|
|
595
|
-
setBlockType: setBlockType2,
|
|
596
|
-
toggleBlockType,
|
|
597
|
-
toggleMark: toggleMark2,
|
|
598
|
-
wrapInList: wrapInList2,
|
|
599
|
-
clear,
|
|
600
|
-
attachFile: (files) => {
|
|
601
|
-
options.attachFile?.(view, files);
|
|
602
|
-
}
|
|
603
|
-
};
|
|
604
|
-
}
|
|
605
|
-
};
|
|
606
|
-
|
|
607
|
-
// src/input.tsx
|
|
608
|
-
var import_react = __toESM(require("react"));
|
|
609
|
-
var import_rxjs = require("rxjs");
|
|
610
|
-
function TextEditorInput({
|
|
611
|
-
ref,
|
|
612
|
-
onChange,
|
|
613
|
-
updateDelay = 0,
|
|
614
|
-
...props
|
|
615
|
-
}) {
|
|
616
|
-
const inputRef = import_react.default.useRef(null);
|
|
617
|
-
(0, import_react.useEffect)(() => {
|
|
618
|
-
const controller = ref.current;
|
|
619
|
-
if (!controller) {
|
|
620
|
-
return;
|
|
621
|
-
}
|
|
622
|
-
const sub = controller.subject.pipe(
|
|
623
|
-
(0, import_rxjs.filter)((tr) => tr.docChanged),
|
|
624
|
-
(0, import_rxjs.debounceTime)(updateDelay)
|
|
625
|
-
).subscribe(() => {
|
|
626
|
-
if (inputRef.current) {
|
|
627
|
-
inputRef.current.value = controller.value;
|
|
628
|
-
const event = new Event("input", { bubbles: true });
|
|
629
|
-
inputRef.current.dispatchEvent(event);
|
|
630
|
-
}
|
|
631
|
-
});
|
|
632
|
-
return () => {
|
|
633
|
-
sub.unsubscribe();
|
|
634
|
-
controller.view.destroy();
|
|
635
|
-
};
|
|
636
|
-
}, []);
|
|
637
|
-
return /* @__PURE__ */ import_react.default.createElement("input", { ...props, ref: inputRef, type: "hidden", onInput: onChange });
|
|
638
|
-
}
|
|
639
|
-
|
|
640
|
-
// src/text_editor_controller.tsx
|
|
641
|
-
var import_prosemirror_state5 = require("prosemirror-state");
|
|
642
|
-
var import_prosemirror_view4 = require("prosemirror-view");
|
|
643
|
-
var commands2 = __toESM(require("prosemirror-commands"));
|
|
644
|
-
var import_prosemirror_keymap = require("prosemirror-keymap");
|
|
645
|
-
|
|
646
|
-
// src/plugins/drag_and_drop.tsx
|
|
647
|
-
var import_prosemirror_state = require("prosemirror-state");
|
|
648
|
-
function dragAndDropPlugin({ attachFile }) {
|
|
649
|
-
return new import_prosemirror_state.Plugin({
|
|
650
|
-
props: {
|
|
651
|
-
handleDOMEvents: {
|
|
652
|
-
drop(view, event) {
|
|
653
|
-
if (!attachFile) {
|
|
654
|
-
return;
|
|
655
|
-
}
|
|
656
|
-
const files = event.dataTransfer?.files;
|
|
657
|
-
if (!files || files.length === 0) {
|
|
658
|
-
return;
|
|
659
|
-
}
|
|
660
|
-
event.preventDefault();
|
|
661
|
-
const pos = view.state.selection.$from.pos || view.posAtCoords({
|
|
662
|
-
left: event.clientX,
|
|
663
|
-
top: event.clientY
|
|
664
|
-
})?.pos || null;
|
|
665
|
-
if (pos === null) {
|
|
666
|
-
return;
|
|
667
|
-
}
|
|
668
|
-
const medias = Array.from(files).filter(
|
|
669
|
-
(file) => file.type.startsWith("image/") || file.type.startsWith("video/")
|
|
670
|
-
);
|
|
671
|
-
attachFile(view, medias);
|
|
672
|
-
return true;
|
|
673
|
-
}
|
|
674
|
-
}
|
|
675
|
-
}
|
|
676
|
-
});
|
|
677
|
-
}
|
|
678
|
-
|
|
679
|
-
// src/plugins/upload_placeholder.tsx
|
|
680
|
-
var import_prosemirror_state2 = require("prosemirror-state");
|
|
681
|
-
var import_prosemirror_view = require("prosemirror-view");
|
|
682
|
-
var uploadPlaceholderPlugin = new import_prosemirror_state2.Plugin({
|
|
683
|
-
state: {
|
|
684
|
-
init() {
|
|
685
|
-
return import_prosemirror_view.DecorationSet.empty;
|
|
686
|
-
},
|
|
687
|
-
apply(tr, set) {
|
|
688
|
-
set = set.map(tr.mapping, tr.doc);
|
|
689
|
-
const action = tr.getMeta(this);
|
|
690
|
-
if (action && action.add) {
|
|
691
|
-
const { type, width, height } = action.add;
|
|
692
|
-
const widget = document.createElement("div");
|
|
693
|
-
widget.className = "upload-placeholder";
|
|
694
|
-
widget.style.width = `100%`;
|
|
695
|
-
if (type.startsWith("image/") || type.startsWith("video/")) {
|
|
696
|
-
widget.style.aspectRatio = `${width} / ${height}`;
|
|
697
|
-
widget.style.maxWidth = `${width}px`;
|
|
698
|
-
} else {
|
|
699
|
-
widget.style.height = "80px";
|
|
700
|
-
}
|
|
701
|
-
const progress = document.createElement("div");
|
|
702
|
-
progress.className = "upload-progress";
|
|
703
|
-
widget.appendChild(progress);
|
|
704
|
-
const deco = import_prosemirror_view.Decoration.widget(action.add.pos, widget, {
|
|
705
|
-
id: action.add.id
|
|
706
|
-
});
|
|
707
|
-
set = set.add(tr.doc, [deco]);
|
|
708
|
-
} else if (action && action.progress) {
|
|
709
|
-
const found = set.find(
|
|
710
|
-
void 0,
|
|
711
|
-
void 0,
|
|
712
|
-
(spec) => spec.id === action.progress.id
|
|
713
|
-
);
|
|
714
|
-
if (found.length) {
|
|
715
|
-
const widget = found[0].type.toDOM;
|
|
716
|
-
const progress = widget.querySelector(".upload-progress");
|
|
717
|
-
if (progress) {
|
|
718
|
-
progress.innerHTML = `${Math.round(action.progress.progress)}%`;
|
|
719
|
-
}
|
|
720
|
-
}
|
|
721
|
-
} else if (action && action.remove) {
|
|
722
|
-
set = set.remove(
|
|
723
|
-
set.find(void 0, void 0, (spec) => spec.id === action.remove.id)
|
|
724
|
-
);
|
|
725
|
-
}
|
|
726
|
-
return set;
|
|
727
|
-
}
|
|
728
|
-
},
|
|
729
|
-
props: {
|
|
730
|
-
decorations(state) {
|
|
731
|
-
return this.getState(state);
|
|
732
|
-
}
|
|
733
|
-
}
|
|
734
|
-
});
|
|
735
|
-
var findPlaceholder = (state, id) => {
|
|
736
|
-
const decos = uploadPlaceholderPlugin.getState(state);
|
|
737
|
-
if (!decos) {
|
|
738
|
-
return null;
|
|
739
|
-
}
|
|
740
|
-
const found = decos.find(void 0, void 0, (spec) => spec.id === id);
|
|
741
|
-
return found.length ? found[0].from : null;
|
|
742
|
-
};
|
|
743
|
-
|
|
744
|
-
// src/plugins/placehoder.tsx
|
|
745
|
-
var import_prosemirror_model2 = require("prosemirror-model");
|
|
746
|
-
var import_prosemirror_state3 = require("prosemirror-state");
|
|
747
|
-
var import_prosemirror_view2 = require("prosemirror-view");
|
|
748
|
-
var getFirstChildDescendants = (view) => {
|
|
749
|
-
const nodes = [];
|
|
750
|
-
view.state.doc?.descendants((n) => {
|
|
751
|
-
nodes.push(n);
|
|
752
|
-
});
|
|
753
|
-
return nodes;
|
|
754
|
-
};
|
|
755
|
-
function placeholderPlugin(text) {
|
|
756
|
-
const update = (view) => {
|
|
757
|
-
const decos = uploadPlaceholderPlugin.getState(view.state);
|
|
758
|
-
if (decos && decos.find().length > 0 || view.state.doc.content.content.some((e) => e.type.name !== "paragraph") || view.state.doc.childCount > 1 || getFirstChildDescendants(view).length > 1 || view.state.doc.textContent) {
|
|
759
|
-
view.dom.removeAttribute("data-placeholder");
|
|
760
|
-
} else {
|
|
761
|
-
view.dom.setAttribute("data-placeholder", text);
|
|
762
|
-
}
|
|
763
|
-
};
|
|
764
|
-
return new import_prosemirror_state3.Plugin({
|
|
765
|
-
view(view) {
|
|
766
|
-
update(view);
|
|
767
|
-
return { update };
|
|
768
|
-
}
|
|
769
|
-
});
|
|
770
|
-
}
|
|
771
|
-
|
|
772
|
-
// src/text_editor_controller.tsx
|
|
773
|
-
var import_prosemirror_history2 = require("prosemirror-history");
|
|
774
|
-
|
|
775
|
-
// src/plugins/keymap.tsx
|
|
776
|
-
var import_prosemirror_state4 = require("prosemirror-state");
|
|
777
|
-
var import_prosemirror_history = require("prosemirror-history");
|
|
778
|
-
var import_prosemirror_commands = require("prosemirror-commands");
|
|
779
|
-
var import_prosemirror_schema_list2 = require("prosemirror-schema-list");
|
|
780
|
-
function buildKeymap(schema) {
|
|
781
|
-
const keys = {};
|
|
782
|
-
function bind(key, cmd) {
|
|
783
|
-
keys[key] = cmd;
|
|
784
|
-
}
|
|
785
|
-
bind("Mod-z", import_prosemirror_history.undo);
|
|
786
|
-
bind("Shift-Mod-z", import_prosemirror_history.redo);
|
|
787
|
-
bind("Mod-y", import_prosemirror_history.redo);
|
|
788
|
-
const li = schema.nodes.list_item;
|
|
789
|
-
bind(
|
|
790
|
-
"Enter",
|
|
791
|
-
(0, import_prosemirror_commands.chainCommands)((0, import_prosemirror_schema_list2.splitListItem)(li), (state, dispatch) => {
|
|
792
|
-
const { $head } = state.selection;
|
|
793
|
-
if ($head.parent.type === state.schema.nodes.paragraph) {
|
|
794
|
-
(0, import_prosemirror_commands.splitBlockAs)((n) => {
|
|
795
|
-
return {
|
|
796
|
-
type: n.type,
|
|
797
|
-
attrs: n.attrs
|
|
798
|
-
};
|
|
799
|
-
})(state, dispatch);
|
|
800
|
-
return true;
|
|
801
|
-
}
|
|
802
|
-
return false;
|
|
803
|
-
})
|
|
804
|
-
);
|
|
805
|
-
bind("ArrowDown", (state, dispatch) => {
|
|
806
|
-
const doc = state.doc;
|
|
807
|
-
const lastNode = doc.lastChild;
|
|
808
|
-
if (lastNode && lastNode.type.name !== "paragraph") {
|
|
809
|
-
const paragraphType = state.schema.nodes.paragraph;
|
|
810
|
-
let tr = state.tr;
|
|
811
|
-
const endPos = doc.content.size;
|
|
812
|
-
tr = tr.insert(endPos, paragraphType.create());
|
|
813
|
-
tr = tr.setSelection(import_prosemirror_state4.TextSelection.create(tr.doc, tr.doc.content.size));
|
|
814
|
-
if (dispatch) {
|
|
815
|
-
dispatch(tr);
|
|
816
|
-
}
|
|
817
|
-
return true;
|
|
818
|
-
}
|
|
819
|
-
return false;
|
|
820
|
-
});
|
|
821
|
-
return keys;
|
|
822
|
-
}
|
|
823
|
-
|
|
824
|
-
// src/cn.ts
|
|
825
|
-
function cn(...classes) {
|
|
826
|
-
return classes.filter(Boolean).join(" ").trim();
|
|
827
|
-
}
|
|
828
|
-
|
|
829
|
-
// src/attach_file.tsx
|
|
830
|
-
var import_prosemirror_view3 = require("prosemirror-view");
|
|
831
|
-
|
|
832
|
-
// src/base64_file_uploader.ts
|
|
833
|
-
var base64FileUploader = async (file) => {
|
|
834
|
-
const base64 = await new Promise((resolve, reject) => {
|
|
835
|
-
const reader = new FileReader();
|
|
836
|
-
reader.onload = () => {
|
|
837
|
-
resolve(reader.result);
|
|
749
|
+
// src/base64_file_uploader.ts
|
|
750
|
+
var base64FileUploader = async (file) => {
|
|
751
|
+
const base64 = await new Promise((resolve, reject) => {
|
|
752
|
+
const reader = new FileReader();
|
|
753
|
+
reader.onload = () => {
|
|
754
|
+
resolve(reader.result);
|
|
838
755
|
};
|
|
839
756
|
reader.onerror = reject;
|
|
840
757
|
reader.readAsDataURL(file);
|
|
@@ -912,129 +829,208 @@ function createAttachFile({
|
|
|
912
829
|
};
|
|
913
830
|
}
|
|
914
831
|
|
|
832
|
+
// src/commands.tsx
|
|
833
|
+
var commands = __toESM(require("prosemirror-commands"));
|
|
834
|
+
var schemaList = __toESM(require("prosemirror-schema-list"));
|
|
835
|
+
var createCommands = (schema, view, options = {}) => {
|
|
836
|
+
{
|
|
837
|
+
const isBlockTypeActive = (node, attrs, excludes = []) => {
|
|
838
|
+
const state = view.state;
|
|
839
|
+
const ranges = state.selection.ranges;
|
|
840
|
+
let active = false;
|
|
841
|
+
for (const range of ranges) {
|
|
842
|
+
const { $from, $to } = range;
|
|
843
|
+
state.doc.nodesBetween($from.pos, $to.pos, (n) => {
|
|
844
|
+
if (active) {
|
|
845
|
+
return true;
|
|
846
|
+
}
|
|
847
|
+
if (n.type !== node || excludes.includes(n.type)) {
|
|
848
|
+
return;
|
|
849
|
+
}
|
|
850
|
+
if (!attrs || Object.keys(attrs).every((key) => n.attrs[key] === attrs[key])) {
|
|
851
|
+
active = true;
|
|
852
|
+
}
|
|
853
|
+
});
|
|
854
|
+
return active;
|
|
855
|
+
}
|
|
856
|
+
};
|
|
857
|
+
const setBlockType2 = (node, attrs) => {
|
|
858
|
+
view.focus();
|
|
859
|
+
const nodeType = schema.nodes[node];
|
|
860
|
+
const command = commands.setBlockType(nodeType, attrs);
|
|
861
|
+
command(view.state, view.dispatch);
|
|
862
|
+
};
|
|
863
|
+
const toggleBlockType = (node, attrs) => {
|
|
864
|
+
view.focus();
|
|
865
|
+
const nodeType = schema.nodes[node];
|
|
866
|
+
const command = commands.setBlockType(nodeType, attrs);
|
|
867
|
+
if (isBlockTypeActive(nodeType, attrs)) {
|
|
868
|
+
command(view.state, view.dispatch);
|
|
869
|
+
}
|
|
870
|
+
};
|
|
871
|
+
const toggleMark2 = (mark, attrs, options2) => {
|
|
872
|
+
view.focus();
|
|
873
|
+
const markType = schema.marks[mark];
|
|
874
|
+
const command = commands.toggleMark(markType, attrs, options2);
|
|
875
|
+
command(view.state, view.dispatch);
|
|
876
|
+
};
|
|
877
|
+
const wrapInList2 = (listType, attrs) => {
|
|
878
|
+
view.focus();
|
|
879
|
+
const nodeType = schema.nodes[listType];
|
|
880
|
+
const command = schemaList.wrapInList(nodeType, attrs);
|
|
881
|
+
command(view.state, view.dispatch);
|
|
882
|
+
};
|
|
883
|
+
const clear = () => {
|
|
884
|
+
const tr = view.state.tr.replaceWith(
|
|
885
|
+
0,
|
|
886
|
+
view.state.doc.content.size,
|
|
887
|
+
schema.nodes.doc.createAndFill()
|
|
888
|
+
);
|
|
889
|
+
view.dispatch(tr);
|
|
890
|
+
};
|
|
891
|
+
return {
|
|
892
|
+
isBlockTypeActive,
|
|
893
|
+
setBlockType: setBlockType2,
|
|
894
|
+
toggleBlockType,
|
|
895
|
+
toggleMark: toggleMark2,
|
|
896
|
+
wrapInList: wrapInList2,
|
|
897
|
+
clear,
|
|
898
|
+
attachFile: (files) => {
|
|
899
|
+
options.attachFile?.(view, files);
|
|
900
|
+
}
|
|
901
|
+
};
|
|
902
|
+
}
|
|
903
|
+
};
|
|
904
|
+
|
|
915
905
|
// src/text_editor_controller.tsx
|
|
916
906
|
var import_prosemirror_model3 = require("prosemirror-model");
|
|
917
907
|
var import_rxjs2 = require("rxjs");
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
908
|
+
var TextEditorController = class {
|
|
909
|
+
schema;
|
|
910
|
+
options;
|
|
911
|
+
props;
|
|
912
|
+
subject;
|
|
913
|
+
view;
|
|
914
|
+
prosemirrorParser;
|
|
915
|
+
prosemirrorSerializer;
|
|
916
|
+
get value() {
|
|
917
|
+
if (this.props.mode === "text") {
|
|
918
|
+
return this.toTextContent();
|
|
919
|
+
}
|
|
920
|
+
return this.toHTML();
|
|
921
|
+
}
|
|
922
|
+
set value(value) {
|
|
923
|
+
const wrap = document.createElement("div");
|
|
924
|
+
wrap.innerHTML = this.toInnerHTML(value);
|
|
925
|
+
const doc = this.prosemirrorParser.parse(wrap);
|
|
926
|
+
const tr = this.view.state.tr.replaceWith(
|
|
927
|
+
0,
|
|
928
|
+
this.view.state.doc.content.size,
|
|
929
|
+
doc.content
|
|
930
|
+
);
|
|
931
|
+
this.view.dispatch(tr);
|
|
932
|
+
}
|
|
933
|
+
constructor(options = {}, props = {}) {
|
|
934
|
+
this.schema = createSchema();
|
|
935
|
+
this.options = options;
|
|
936
|
+
this.props = props;
|
|
937
|
+
this.subject = new import_rxjs2.Subject();
|
|
938
|
+
this.prosemirrorParser = import_prosemirror_model3.DOMParser.fromSchema(this.schema);
|
|
939
|
+
this.prosemirrorSerializer = import_prosemirror_model3.DOMSerializer.fromSchema(this.schema);
|
|
940
|
+
}
|
|
941
|
+
toInnerHTML(value) {
|
|
942
|
+
if (this.props.mode === "text") {
|
|
932
943
|
return value.split("\n").map((line) => `<p>${line}</p>`).join("");
|
|
933
944
|
}
|
|
934
945
|
return value;
|
|
935
|
-
}
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
946
|
+
}
|
|
947
|
+
attachFile(files) {
|
|
948
|
+
return createAttachFile({
|
|
949
|
+
schema: this.schema,
|
|
950
|
+
generateMetadata: this.options.attachFile?.generateMetadata,
|
|
951
|
+
uploadFile: this.options.attachFile?.uploadFile
|
|
952
|
+
})(this.view, files);
|
|
953
|
+
}
|
|
954
|
+
bind(container) {
|
|
955
|
+
const wrapper = document.createElement("div");
|
|
956
|
+
wrapper.innerHTML = this.toInnerHTML(
|
|
957
|
+
this.props.defaultValue ? String(this.props.defaultValue) : ""
|
|
958
|
+
);
|
|
959
|
+
this.view = new import_prosemirror_view4.EditorView(container, {
|
|
960
|
+
...this.props.editor,
|
|
961
|
+
attributes: (state) => {
|
|
962
|
+
const propsAttributes = (() => {
|
|
963
|
+
if (typeof this.props.editor?.attributes === "function") {
|
|
964
|
+
return this.props.editor.attributes(state);
|
|
965
|
+
}
|
|
966
|
+
return this.props.editor?.attributes;
|
|
967
|
+
})();
|
|
968
|
+
return {
|
|
969
|
+
...propsAttributes,
|
|
970
|
+
class: cn(this.options?.className, propsAttributes?.class),
|
|
971
|
+
spellcheck: propsAttributes?.spellcheck || "false",
|
|
972
|
+
style: this.options.style || "width: 100%; height: inherit; outline: none;"
|
|
973
|
+
};
|
|
974
|
+
},
|
|
975
|
+
state: import_prosemirror_state5.EditorState.create({
|
|
976
|
+
...this.props.state,
|
|
977
|
+
schema: this.props.state?.schema || this.schema,
|
|
978
|
+
doc: this.props.state?.doc || this.prosemirrorParser.parse(wrapper),
|
|
979
|
+
plugins: [
|
|
980
|
+
...this.props.state?.plugins || [],
|
|
981
|
+
(0, import_prosemirror_history2.history)({
|
|
982
|
+
newGroupDelay: this.props.updateDelay
|
|
983
|
+
}),
|
|
984
|
+
(0, import_prosemirror_keymap.keymap)(buildKeymap(this.schema)),
|
|
985
|
+
(0, import_prosemirror_keymap.keymap)(commands2.baseKeymap),
|
|
986
|
+
uploadPlaceholderPlugin,
|
|
987
|
+
dragAndDropPlugin({
|
|
988
|
+
attachFile: (view, files) => this.attachFile(files)
|
|
989
|
+
}),
|
|
990
|
+
this.props.placeholder && placeholderPlugin(this.props.placeholder)
|
|
991
|
+
].filter((e) => !!e)
|
|
992
|
+
}),
|
|
993
|
+
dispatchTransaction: (tr) => {
|
|
994
|
+
let result;
|
|
995
|
+
if (this.props.editor?.dispatchTransaction) {
|
|
996
|
+
result = this.props.editor.dispatchTransaction(tr);
|
|
997
|
+
} else {
|
|
998
|
+
this.view?.updateState(this.view.state.apply(tr));
|
|
948
999
|
}
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
return {
|
|
952
|
-
...propsAttributes,
|
|
953
|
-
class: cn(options?.className, propsAttributes?.class),
|
|
954
|
-
spellcheck: propsAttributes?.spellcheck || "false",
|
|
955
|
-
style: options.style || "width: 100%; height: inherit; outline: none;"
|
|
956
|
-
};
|
|
957
|
-
},
|
|
958
|
-
state: import_prosemirror_state5.EditorState.create({
|
|
959
|
-
...state,
|
|
960
|
-
schema: state?.schema || schema,
|
|
961
|
-
doc: state?.doc || prosemirrorParser.parse(wrapper),
|
|
962
|
-
plugins: [
|
|
963
|
-
...state?.plugins || [],
|
|
964
|
-
(0, import_prosemirror_history2.history)({
|
|
965
|
-
newGroupDelay: updateDelay
|
|
966
|
-
}),
|
|
967
|
-
(0, import_prosemirror_keymap.keymap)(buildKeymap(schema)),
|
|
968
|
-
(0, import_prosemirror_keymap.keymap)(commands2.baseKeymap),
|
|
969
|
-
uploadPlaceholderPlugin,
|
|
970
|
-
dragAndDropPlugin({
|
|
971
|
-
attachFile
|
|
972
|
-
}),
|
|
973
|
-
placeholder && placeholderPlugin(placeholder)
|
|
974
|
-
].filter((e) => !!e)
|
|
975
|
-
}),
|
|
976
|
-
dispatchTransaction(tr) {
|
|
977
|
-
let result;
|
|
978
|
-
if (editor?.dispatchTransaction) {
|
|
979
|
-
result = editor.dispatchTransaction(tr);
|
|
980
|
-
} else {
|
|
981
|
-
view.updateState(view.state.apply(tr));
|
|
1000
|
+
this.subject.next(tr);
|
|
1001
|
+
return result;
|
|
982
1002
|
}
|
|
983
|
-
|
|
984
|
-
|
|
1003
|
+
});
|
|
1004
|
+
if (this.props.autoFocus) {
|
|
1005
|
+
this.view?.focus();
|
|
985
1006
|
}
|
|
986
|
-
});
|
|
987
|
-
function setValue(value) {
|
|
988
|
-
const wrap = document.createElement("div");
|
|
989
|
-
wrap.innerHTML = toInnerHTML(value);
|
|
990
|
-
const doc = prosemirrorParser.parse(wrap);
|
|
991
|
-
const tr = view.state.tr.replaceWith(
|
|
992
|
-
0,
|
|
993
|
-
view.state.doc.content.size,
|
|
994
|
-
doc.content
|
|
995
|
-
);
|
|
996
|
-
view.dispatch(tr);
|
|
997
1007
|
}
|
|
998
|
-
|
|
999
|
-
const fragment = prosemirrorSerializer.serializeFragment(
|
|
1000
|
-
view.state.doc.content
|
|
1008
|
+
toHTML() {
|
|
1009
|
+
const fragment = this.prosemirrorSerializer.serializeFragment(
|
|
1010
|
+
this.view.state.doc.content
|
|
1001
1011
|
);
|
|
1002
|
-
const
|
|
1003
|
-
|
|
1004
|
-
return
|
|
1012
|
+
const container = document.createElement("div");
|
|
1013
|
+
container.appendChild(fragment);
|
|
1014
|
+
return container.innerHTML;
|
|
1005
1015
|
}
|
|
1006
|
-
|
|
1007
|
-
const
|
|
1008
|
-
return
|
|
1016
|
+
toTextContent() {
|
|
1017
|
+
const state = this.view.state;
|
|
1018
|
+
return state.doc.textBetween(0, state.doc.content.size, "\n");
|
|
1009
1019
|
}
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
},
|
|
1020
|
-
get value() {
|
|
1021
|
-
switch (mode) {
|
|
1022
|
-
case "text":
|
|
1023
|
-
return toTextContent();
|
|
1024
|
-
default:
|
|
1025
|
-
return toHTML();
|
|
1026
|
-
}
|
|
1027
|
-
},
|
|
1028
|
-
commands: textEditorCommands
|
|
1029
|
-
};
|
|
1030
|
-
return textEditorController;
|
|
1031
|
-
}
|
|
1020
|
+
get commands() {
|
|
1021
|
+
return createCommands(this.schema, this.view, {
|
|
1022
|
+
attachFile: (view, files) => this.attachFile(files)
|
|
1023
|
+
});
|
|
1024
|
+
}
|
|
1025
|
+
dispose() {
|
|
1026
|
+
this.view?.destroy();
|
|
1027
|
+
}
|
|
1028
|
+
};
|
|
1032
1029
|
|
|
1033
1030
|
// src/create_text_editor.tsx
|
|
1034
1031
|
function createTextEditor(options = {}) {
|
|
1035
|
-
const schema = createSchema();
|
|
1036
1032
|
function Component({
|
|
1037
|
-
|
|
1033
|
+
controller: externalController,
|
|
1038
1034
|
className,
|
|
1039
1035
|
autoFocus,
|
|
1040
1036
|
onChange,
|
|
@@ -1047,45 +1043,33 @@ function createTextEditor(options = {}) {
|
|
|
1047
1043
|
...props
|
|
1048
1044
|
} = {}) {
|
|
1049
1045
|
const containerRef = (0, import_react3.useRef)(null);
|
|
1050
|
-
const
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
mode,
|
|
1061
|
-
state,
|
|
1062
|
-
editor,
|
|
1063
|
-
defaultValue,
|
|
1064
|
-
updateDelay,
|
|
1065
|
-
placeholder
|
|
1066
|
-
}
|
|
1067
|
-
);
|
|
1068
|
-
controllerRef.current = textEditorController;
|
|
1069
|
-
return textEditorController;
|
|
1070
|
-
},
|
|
1046
|
+
const innerController = (0, import_react2.useMemo)(
|
|
1047
|
+
() => new TextEditorController(options, {
|
|
1048
|
+
mode,
|
|
1049
|
+
state,
|
|
1050
|
+
editor,
|
|
1051
|
+
autoFocus,
|
|
1052
|
+
placeholder,
|
|
1053
|
+
updateDelay,
|
|
1054
|
+
defaultValue
|
|
1055
|
+
}),
|
|
1071
1056
|
[]
|
|
1072
1057
|
);
|
|
1058
|
+
const controller = externalController || innerController;
|
|
1073
1059
|
(0, import_react3.useEffect)(() => {
|
|
1074
|
-
const
|
|
1075
|
-
if (!
|
|
1060
|
+
const container = containerRef.current;
|
|
1061
|
+
if (!container) {
|
|
1076
1062
|
return;
|
|
1077
1063
|
}
|
|
1078
|
-
|
|
1079
|
-
controller.view.focus();
|
|
1080
|
-
}
|
|
1064
|
+
controller.bind(container);
|
|
1081
1065
|
return () => {
|
|
1082
|
-
controller.
|
|
1066
|
+
controller.dispose();
|
|
1083
1067
|
};
|
|
1084
|
-
}, []);
|
|
1068
|
+
}, [controller]);
|
|
1085
1069
|
return /* @__PURE__ */ import_react2.default.createElement(import_react2.default.Fragment, null, /* @__PURE__ */ import_react2.default.createElement("div", { ...props, ref: containerRef, className }), /* @__PURE__ */ import_react2.default.createElement(
|
|
1086
1070
|
TextEditorInput,
|
|
1087
1071
|
{
|
|
1088
|
-
|
|
1072
|
+
controller,
|
|
1089
1073
|
updateDelay,
|
|
1090
1074
|
defaultValue,
|
|
1091
1075
|
onChange
|