dn-react-text-editor 0.1.2 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/README.md +19 -0
  2. package/dist/attach_file.d.mts +20 -22
  3. package/dist/attach_file.d.ts +20 -22
  4. package/dist/attach_file.js +5 -5
  5. package/dist/attach_file.mjs +5 -4
  6. package/dist/base64_file_uploader.d.mts +6 -0
  7. package/dist/base64_file_uploader.d.ts +6 -0
  8. package/dist/{plugins/trailing_paragraph.js → base64_file_uploader.js} +19 -22
  9. package/dist/base64_file_uploader.mjs +18 -0
  10. package/dist/commands.d.mts +23 -0
  11. package/dist/commands.d.ts +23 -0
  12. package/dist/commands.js +110 -0
  13. package/dist/commands.mjs +75 -0
  14. package/dist/create_text_editor.d.mts +28 -0
  15. package/dist/create_text_editor.d.ts +28 -0
  16. package/dist/create_text_editor.js +1093 -0
  17. package/dist/create_text_editor.mjs +1064 -0
  18. package/dist/html.d.mts +8 -0
  19. package/dist/html.d.ts +8 -0
  20. package/dist/html.js +136 -0
  21. package/dist/html.mjs +98 -0
  22. package/dist/index.d.mts +7 -4
  23. package/dist/index.d.ts +7 -4
  24. package/dist/index.js +782 -365
  25. package/dist/index.mjs +777 -360
  26. package/dist/input.d.mts +21 -0
  27. package/dist/input.d.ts +21 -0
  28. package/dist/input.js +70 -0
  29. package/dist/input.mjs +37 -0
  30. package/dist/plugins/drag_and_drop.d.mts +1 -1
  31. package/dist/plugins/drag_and_drop.d.ts +1 -1
  32. package/dist/plugins/drag_and_drop.js +3 -0
  33. package/dist/plugins/drag_and_drop.mjs +3 -0
  34. package/dist/plugins/highlighter.d.mts +6 -0
  35. package/dist/plugins/highlighter.d.ts +6 -0
  36. package/dist/plugins/highlighter.js +105 -0
  37. package/dist/plugins/highlighter.mjs +69 -0
  38. package/dist/plugins/keymap.js +17 -0
  39. package/dist/plugins/keymap.mjs +17 -0
  40. package/dist/schema.d.mts +2 -2
  41. package/dist/schema.d.ts +2 -2
  42. package/dist/schema.js +255 -14
  43. package/dist/schema.mjs +245 -14
  44. package/dist/text_editor_controller.d.mts +46 -0
  45. package/dist/text_editor_controller.d.ts +46 -0
  46. package/dist/text_editor_controller.js +503 -0
  47. package/dist/text_editor_controller.mjs +470 -0
  48. package/package.json +3 -1
  49. package/dist/plugins/trailing_paragraph.d.mts +0 -5
  50. package/dist/plugins/trailing_paragraph.d.ts +0 -5
  51. package/dist/plugins/trailing_paragraph.mjs +0 -21
  52. package/dist/text_editor.d.mts +0 -37
  53. package/dist/text_editor.d.ts +0 -37
  54. package/dist/text_editor.js +0 -722
  55. package/dist/text_editor.mjs +0 -692
package/dist/index.js CHANGED
@@ -30,185 +30,93 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
- base64ImageUploader: () => base64ImageUploader,
34
33
  createAttachFile: () => createAttachFile,
34
+ createInnerHTML: () => createInnerHTML,
35
35
  createSchema: () => createSchema,
36
- createTextEditor: () => createTextEditor
36
+ createTextEditor: () => createTextEditor,
37
+ createTextEditorView: () => createTextEditorView
37
38
  });
38
39
  module.exports = __toCommonJS(index_exports);
39
40
 
40
- // src/text_editor.tsx
41
- var import_react = __toESM(require("react"));
42
- var import_prosemirror_state4 = require("prosemirror-state");
43
- var import_prosemirror_view4 = require("prosemirror-view");
44
- var import_react2 = require("react");
45
- var import_prosemirror_commands2 = require("prosemirror-commands");
46
- var import_prosemirror_keymap = require("prosemirror-keymap");
47
-
48
- // src/plugins/drag_and_drop.tsx
49
- var import_prosemirror_state = require("prosemirror-state");
50
- function dragAndDropPlugin({ attachFile }) {
51
- return new import_prosemirror_state.Plugin({
52
- props: {
53
- handleDOMEvents: {
54
- drop(view, event) {
55
- const files = event.dataTransfer?.files;
56
- if (!files || files.length === 0) {
57
- return;
58
- }
59
- event.preventDefault();
60
- const pos = view.state.selection.$from.pos || view.posAtCoords({
61
- left: event.clientX,
62
- top: event.clientY
63
- })?.pos || null;
64
- if (pos === null) {
65
- return;
66
- }
67
- const medias = Array.from(files).filter(
68
- (file) => file.type.startsWith("image/") || file.type.startsWith("video/")
69
- );
70
- attachFile(view, medias);
71
- return true;
72
- }
73
- }
74
- }
75
- });
76
- }
77
-
78
- // src/plugins/upload_placeholder.tsx
79
- var import_prosemirror_state2 = require("prosemirror-state");
80
- var import_prosemirror_view = require("prosemirror-view");
81
- var uploadPlaceholderPlugin = new import_prosemirror_state2.Plugin({
82
- state: {
83
- init() {
84
- return import_prosemirror_view.DecorationSet.empty;
85
- },
86
- apply(tr, set) {
87
- set = set.map(tr.mapping, tr.doc);
88
- const action = tr.getMeta(this);
89
- if (action && action.add) {
90
- const { type, width, height } = action.add;
91
- const widget = document.createElement("div");
92
- widget.className = "upload-placeholder";
93
- widget.style.width = `100%`;
94
- if (type.startsWith("image/") || type.startsWith("video/")) {
95
- widget.style.aspectRatio = `${width} / ${height}`;
96
- widget.style.maxWidth = `${width}px`;
97
- } else {
98
- widget.style.height = "80px";
99
- }
100
- const progress = document.createElement("div");
101
- progress.className = "upload-progress";
102
- widget.appendChild(progress);
103
- const deco = import_prosemirror_view.Decoration.widget(action.add.pos, widget, {
104
- id: action.add.id
105
- });
106
- set = set.add(tr.doc, [deco]);
107
- } else if (action && action.progress) {
108
- const found = set.find(
109
- void 0,
110
- void 0,
111
- (spec) => spec.id === action.progress.id
112
- );
113
- if (found.length) {
114
- const widget = found[0].type.toDOM;
115
- const progress = widget.querySelector(".upload-progress");
116
- if (progress) {
117
- progress.innerHTML = `${Math.round(action.progress.progress)}%`;
118
- }
119
- }
120
- } else if (action && action.remove) {
121
- set = set.remove(
122
- set.find(void 0, void 0, (spec) => spec.id === action.remove.id)
123
- );
124
- }
125
- return set;
126
- }
127
- },
128
- props: {
129
- decorations(state) {
130
- return this.getState(state);
131
- }
132
- }
133
- });
134
- var findPlaceholder = (state, id) => {
135
- const decos = uploadPlaceholderPlugin.getState(state);
136
- if (!decos) {
137
- return null;
138
- }
139
- const found = decos.find(void 0, void 0, (spec) => spec.id === id);
140
- return found.length ? found[0].from : null;
141
- };
41
+ // src/create_text_editor.tsx
42
+ var import_react2 = __toESM(require("react"));
43
+ var import_prosemirror_state6 = require("prosemirror-state");
44
+ var import_prosemirror_view5 = require("prosemirror-view");
45
+ var import_react3 = require("react");
142
46
 
143
- // src/plugins/placehoder.tsx
47
+ // src/schema.tsx
144
48
  var import_prosemirror_model = require("prosemirror-model");
145
- var import_prosemirror_state3 = require("prosemirror-state");
146
- var import_prosemirror_view2 = require("prosemirror-view");
147
- var getFirstChildDescendants = (view) => {
148
- const nodes = [];
149
- view.state.doc?.descendants((n) => {
150
- nodes.push(n);
151
- });
152
- return nodes;
153
- };
154
- function placeholderPlugin(text) {
155
- const update = (view) => {
156
- const decos = uploadPlaceholderPlugin.getState(view.state);
157
- 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) {
158
- view.dom.removeAttribute("data-placeholder");
159
- } else {
160
- view.dom.setAttribute("data-placeholder", text);
161
- }
162
- };
163
- return new import_prosemirror_state3.Plugin({
164
- view(view) {
165
- update(view);
166
- return { update };
167
- }
168
- });
169
- }
170
-
171
- // src/text_editor.tsx
172
- var import_prosemirror_model3 = require("prosemirror-model");
173
- var import_prosemirror_history2 = require("prosemirror-history");
174
-
175
- // src/plugins/keymap.tsx
176
- var import_prosemirror_history = require("prosemirror-history");
177
- var import_prosemirror_commands = require("prosemirror-commands");
178
49
  var import_prosemirror_schema_list = require("prosemirror-schema-list");
179
- function buildKeymap(schema) {
180
- const keys = {};
181
- function bind(key, cmd) {
182
- keys[key] = cmd;
183
- }
184
- bind("Mod-z", import_prosemirror_history.undo);
185
- bind("Shift-Mod-z", import_prosemirror_history.redo);
186
- bind("Mod-y", import_prosemirror_history.redo);
187
- const li = schema.nodes.list_item;
188
- bind(
189
- "Enter",
190
- (0, import_prosemirror_commands.chainCommands)((0, import_prosemirror_schema_list.splitListItem)(li), (state, dispatch) => {
191
- const { $head } = state.selection;
192
- if ($head.parent.type === state.schema.nodes.paragraph) {
193
- (0, import_prosemirror_commands.splitBlockAs)((n) => {
194
- return {
195
- type: n.type,
196
- attrs: n.attrs
197
- };
198
- })(state, dispatch);
199
- return true;
200
- }
201
- return false;
202
- })
203
- );
204
- return keys;
205
- }
50
+
51
+ // src/plugins/highlighter.ts
52
+ var import_highlight = __toESM(require("highlight.js"));
53
+ var import_bash = __toESM(require("highlight.js/lib/languages/bash"));
54
+ var import_c = __toESM(require("highlight.js/lib/languages/c"));
55
+ var import_cpp = __toESM(require("highlight.js/lib/languages/cpp"));
56
+ var import_css = __toESM(require("highlight.js/lib/languages/css"));
57
+ var import_java = __toESM(require("highlight.js/lib/languages/java"));
58
+ var import_typescript = __toESM(require("highlight.js/lib/languages/typescript"));
59
+ var import_javascript = __toESM(require("highlight.js/lib/languages/javascript"));
60
+ var import_json = __toESM(require("highlight.js/lib/languages/json"));
61
+ var import_xml = __toESM(require("highlight.js/lib/languages/xml"));
62
+ var import_python = __toESM(require("highlight.js/lib/languages/python"));
63
+ var import_dart = __toESM(require("highlight.js/lib/languages/dart"));
64
+ var import_csharp = __toESM(require("highlight.js/lib/languages/csharp"));
65
+ var import_markdown = __toESM(require("highlight.js/lib/languages/markdown"));
66
+ var import_nginx = __toESM(require("highlight.js/lib/languages/nginx"));
67
+ var import_php = __toESM(require("highlight.js/lib/languages/php"));
68
+ var import_ruby = __toESM(require("highlight.js/lib/languages/ruby"));
69
+ var import_sql = __toESM(require("highlight.js/lib/languages/sql"));
70
+ var import_swift = __toESM(require("highlight.js/lib/languages/swift"));
71
+ var import_yaml = __toESM(require("highlight.js/lib/languages/yaml"));
72
+ var import_rust = __toESM(require("highlight.js/lib/languages/rust"));
73
+ import_highlight.default.registerLanguage("bash", import_bash.default);
74
+ import_highlight.default.registerLanguage("c", import_c.default);
75
+ import_highlight.default.registerLanguage("cpp", import_cpp.default);
76
+ import_highlight.default.registerLanguage("css", import_css.default);
77
+ import_highlight.default.registerLanguage("java", import_java.default);
78
+ import_highlight.default.registerLanguage("markdown", import_markdown.default);
79
+ import_highlight.default.registerLanguage("nginx", import_nginx.default);
80
+ import_highlight.default.registerLanguage("php", import_php.default);
81
+ import_highlight.default.registerLanguage("ruby", import_ruby.default);
82
+ import_highlight.default.registerLanguage("sql", import_sql.default);
83
+ import_highlight.default.registerLanguage("swift", import_swift.default);
84
+ import_highlight.default.registerLanguage("yaml", import_yaml.default);
85
+ import_highlight.default.registerLanguage("rust", import_rust.default);
86
+ import_highlight.default.registerLanguage("json", import_json.default);
87
+ import_highlight.default.registerLanguage("javascript", import_javascript.default);
88
+ import_highlight.default.registerLanguage("typescript", import_typescript.default);
89
+ import_highlight.default.registerLanguage("xml", import_xml.default);
90
+ import_highlight.default.registerLanguage("python", import_python.default);
91
+ import_highlight.default.registerLanguage("dart", import_dart.default);
92
+ import_highlight.default.registerLanguage("csharp", import_csharp.default);
93
+ var supportedLanguages = [
94
+ "bash",
95
+ "c",
96
+ "cpp",
97
+ "css",
98
+ "java",
99
+ "markdown",
100
+ "nginx",
101
+ "php",
102
+ "ruby",
103
+ "sql",
104
+ "swift",
105
+ "yaml",
106
+ "rust",
107
+ "json",
108
+ "javascript",
109
+ "typescript",
110
+ "xml",
111
+ "python",
112
+ "dart",
113
+ "csharp"
114
+ ];
115
+ var highlighter = import_highlight.default;
206
116
 
207
117
  // src/schema.tsx
208
- var import_prosemirror_model2 = require("prosemirror-model");
209
- var import_prosemirror_schema_list2 = require("prosemirror-schema-list");
210
- function createSchema() {
211
- const customSchema = new import_prosemirror_model2.Schema({
118
+ function createSchema(spec = { nodes: {}, marks: {} }) {
119
+ const customSchema = new import_prosemirror_model.Schema({
212
120
  nodes: {
213
121
  doc: { content: "block+" },
214
122
  paragraph: {
@@ -373,70 +281,235 @@ function createSchema() {
373
281
  }
374
282
  ];
375
283
  }
376
- }
377
- },
378
- marks: {
379
- link: {
284
+ },
285
+ video: {
286
+ inline: false,
287
+ group: "block",
288
+ draggable: true,
380
289
  attrs: {
381
- href: { default: "" },
382
- title: { default: null }
290
+ src: { validate: "string" },
291
+ title: {
292
+ default: null,
293
+ validate: "string|null"
294
+ },
295
+ width: {
296
+ default: null,
297
+ validate: "number|null"
298
+ },
299
+ height: {
300
+ default: null,
301
+ validate: "number|null"
302
+ },
303
+ poster: {
304
+ default: null,
305
+ validate: "string|null"
306
+ }
383
307
  },
384
- inclusive: false,
385
308
  parseDOM: [
386
309
  {
387
- tag: "a[href]",
310
+ tag: "video",
388
311
  getAttrs(dom) {
389
312
  return {
390
- href: dom.getAttribute("href"),
391
- title: dom.getAttribute("title")
313
+ src: dom.getAttribute("src"),
314
+ title: dom.getAttribute("title"),
315
+ width: dom.getAttribute("width"),
316
+ height: dom.getAttribute("height"),
317
+ poster: dom.getAttribute("poster")
392
318
  };
393
319
  }
394
320
  }
395
321
  ],
396
322
  toDOM(node) {
397
- const { href, title } = node.attrs;
398
- const target = "_blank";
399
- const rel = "noopener noreferrer";
323
+ const { src, title, width, height, poster } = node.attrs;
400
324
  return [
401
- "a",
402
- { href, title: title || href, target, rel },
403
- 0
325
+ "video",
326
+ {
327
+ src,
328
+ title,
329
+ poster,
330
+ width,
331
+ height,
332
+ playsinline: "true",
333
+ controls: "controls",
334
+ style: `aspect-ratio: ${width} / ${height}`
335
+ }
404
336
  ];
405
337
  }
406
338
  },
407
- bold: {
408
- parseDOM: [
409
- { tag: "strong" },
410
- {
411
- tag: "b",
412
- getAttrs: (node) => node.style.fontWeight != "normal" && null
339
+ iframe: {
340
+ group: "block",
341
+ draggable: true,
342
+ attrs: {
343
+ src: { validate: "string" },
344
+ title: {
345
+ default: null,
346
+ validate: "string|null"
413
347
  },
414
- {
415
- style: "font-weight=400",
416
- clearMark: (m) => m.type.name == "strong"
348
+ width: {
349
+ default: null,
350
+ validate: "number|null"
417
351
  },
418
- {
419
- style: "font-weight",
420
- getAttrs: (value) => /^(bold(er)?|[5-9]\d{2,})$/.test(value) && null
352
+ height: {
353
+ default: null,
354
+ validate: "number|null"
355
+ },
356
+ allow: {
357
+ default: null,
358
+ validate: "string|null"
359
+ },
360
+ allowfullscreen: {
361
+ default: null,
362
+ validate: "string|null"
363
+ },
364
+ referrerPolicy: {
365
+ default: null,
366
+ validate: "string|null"
367
+ },
368
+ style: {
369
+ default: null,
370
+ validate: "string|null"
421
371
  }
422
- ],
423
- toDOM() {
424
- return ["strong", 0];
425
- }
426
- },
427
- italic: {
372
+ },
428
373
  parseDOM: [
429
- { tag: "em" },
430
- { tag: "i" },
431
- { style: "font-style=italic" },
432
374
  {
433
- style: "font-style=normal",
434
- clearMark: (m) => m.type.name == "em"
435
- }
436
- ],
437
- toDOM() {
438
- return ["em", 0];
439
- }
375
+ tag: "iframe[src]",
376
+ getAttrs(dom) {
377
+ return {
378
+ src: dom.getAttribute("src"),
379
+ title: dom.getAttribute("title"),
380
+ width: dom.getAttribute("width"),
381
+ height: dom.getAttribute("height"),
382
+ style: dom.getAttribute("style"),
383
+ allow: dom.getAttribute("allow"),
384
+ allowfullscreen: dom.getAttribute("allowfullscreen"),
385
+ referrerpolicy: dom.getAttribute("referrerpolicy")
386
+ };
387
+ }
388
+ }
389
+ ],
390
+ toDOM(node) {
391
+ const {
392
+ src,
393
+ title,
394
+ width,
395
+ height,
396
+ allow,
397
+ allowfullscreen,
398
+ referrerpolicy,
399
+ style
400
+ } = node.attrs;
401
+ return [
402
+ "iframe",
403
+ {
404
+ src,
405
+ title,
406
+ width,
407
+ height,
408
+ style,
409
+ allow,
410
+ allowfullscreen,
411
+ referrerpolicy,
412
+ frameborder: "0"
413
+ }
414
+ ];
415
+ }
416
+ },
417
+ blockquote: {
418
+ content: "block+",
419
+ group: "block",
420
+ defining: true,
421
+ parseDOM: [{ tag: "blockquote" }],
422
+ toDOM() {
423
+ return ["blockquote", 0];
424
+ }
425
+ },
426
+ code_block: {
427
+ content: "text*",
428
+ marks: "",
429
+ group: "block",
430
+ code: true,
431
+ defining: true,
432
+ parseDOM: [{ tag: "pre", preserveWhitespace: "full" }],
433
+ toDOM(node) {
434
+ const auto = highlighter.highlightAuto(
435
+ node.textContent,
436
+ supportedLanguages
437
+ );
438
+ return [
439
+ "pre",
440
+ {
441
+ class: "hljs"
442
+ },
443
+ [
444
+ "code",
445
+ {
446
+ class: `language-${auto.language}`
447
+ },
448
+ 0
449
+ ]
450
+ ];
451
+ }
452
+ },
453
+ ...spec.nodes
454
+ },
455
+ marks: {
456
+ link: {
457
+ attrs: {
458
+ href: { default: "" },
459
+ title: { default: null }
460
+ },
461
+ inclusive: false,
462
+ parseDOM: [
463
+ {
464
+ tag: "a[href]",
465
+ getAttrs(dom) {
466
+ return {
467
+ href: dom.getAttribute("href"),
468
+ title: dom.getAttribute("title")
469
+ };
470
+ }
471
+ }
472
+ ],
473
+ toDOM(node) {
474
+ const { href, title } = node.attrs;
475
+ const target = "_blank";
476
+ const rel = "noopener noreferrer";
477
+ return ["a", { href, title: title || href, target, rel }, 0];
478
+ }
479
+ },
480
+ bold: {
481
+ parseDOM: [
482
+ { tag: "strong" },
483
+ {
484
+ tag: "b",
485
+ getAttrs: (node) => node.style.fontWeight != "normal" && null
486
+ },
487
+ {
488
+ style: "font-weight=400",
489
+ clearMark: (m) => m.type.name == "strong"
490
+ },
491
+ {
492
+ style: "font-weight",
493
+ getAttrs: (value) => /^(bold(er)?|[5-9]\d{2,})$/.test(value) && null
494
+ }
495
+ ],
496
+ toDOM() {
497
+ return ["strong", 0];
498
+ }
499
+ },
500
+ italic: {
501
+ parseDOM: [
502
+ { tag: "em" },
503
+ { tag: "i" },
504
+ { style: "font-style=italic" },
505
+ {
506
+ style: "font-style=normal",
507
+ clearMark: (m) => m.type.name == "em"
508
+ }
509
+ ],
510
+ toDOM() {
511
+ return ["em", 0];
512
+ }
440
513
  },
441
514
  underline: {
442
515
  parseDOM: [
@@ -449,22 +522,310 @@ function createSchema() {
449
522
  toDOM() {
450
523
  return ["u", 0];
451
524
  }
452
- }
453
- }
525
+ },
526
+ ...spec.marks
527
+ },
528
+ topNode: spec.topNode
454
529
  });
455
- const prosemirrorSchema = new import_prosemirror_model2.Schema({
456
- nodes: (0, import_prosemirror_schema_list2.addListNodes)(
457
- customSchema.spec.nodes,
458
- "paragraph block*",
459
- "block"
460
- ),
530
+ const prosemirrorSchema = new import_prosemirror_model.Schema({
531
+ nodes: (0, import_prosemirror_schema_list.addListNodes)(customSchema.spec.nodes, "paragraph block*", "block"),
461
532
  marks: customSchema.spec.marks
462
533
  });
463
534
  return prosemirrorSchema;
464
535
  }
465
536
 
466
- // src/text_editor.tsx
537
+ // src/create_text_editor.tsx
538
+ var import_rxjs3 = require("rxjs");
539
+
540
+ // src/commands.tsx
541
+ var commands = __toESM(require("prosemirror-commands"));
542
+ var schemaList = __toESM(require("prosemirror-schema-list"));
543
+ var createCommands = (schema, view, options = {}) => {
544
+ {
545
+ const isBlockTypeActive = (node, attrs, excludes = []) => {
546
+ const state = view.state;
547
+ const ranges = state.selection.ranges;
548
+ let active = false;
549
+ for (const range of ranges) {
550
+ const { $from, $to } = range;
551
+ state.doc.nodesBetween($from.pos, $to.pos, (n) => {
552
+ if (active) {
553
+ return true;
554
+ }
555
+ if (n.type !== node || excludes.includes(n.type)) {
556
+ return;
557
+ }
558
+ if (!attrs || Object.keys(attrs).every((key) => n.attrs[key] === attrs[key])) {
559
+ active = true;
560
+ }
561
+ });
562
+ return active;
563
+ }
564
+ };
565
+ const setBlockType2 = (node, attrs) => {
566
+ view.focus();
567
+ const nodeType = schema.nodes[node];
568
+ const command = commands.setBlockType(nodeType, attrs);
569
+ command(view.state, view.dispatch);
570
+ };
571
+ const toggleBlockType = (node, attrs) => {
572
+ view.focus();
573
+ const nodeType = schema.nodes[node];
574
+ const command = commands.setBlockType(nodeType, attrs);
575
+ if (isBlockTypeActive(nodeType, attrs)) {
576
+ command(view.state, view.dispatch);
577
+ }
578
+ };
579
+ const toggleMark2 = (mark, attrs, options2) => {
580
+ view.focus();
581
+ const markType = schema.marks[mark];
582
+ const command = commands.toggleMark(markType, attrs, options2);
583
+ command(view.state, view.dispatch);
584
+ };
585
+ const wrapInList2 = (listType, attrs) => {
586
+ view.focus();
587
+ const nodeType = schema.nodes[listType];
588
+ const command = schemaList.wrapInList(nodeType, attrs);
589
+ command(view.state, view.dispatch);
590
+ };
591
+ const clear = () => {
592
+ const tr = view.state.tr.replaceWith(
593
+ 0,
594
+ view.state.doc.content.size,
595
+ schema.nodes.doc.createAndFill()
596
+ );
597
+ view.dispatch(tr);
598
+ };
599
+ return {
600
+ isBlockTypeActive,
601
+ setBlockType: setBlockType2,
602
+ toggleBlockType,
603
+ toggleMark: toggleMark2,
604
+ wrapInList: wrapInList2,
605
+ clear,
606
+ attachFile: (files) => {
607
+ options.attachFile?.(view, files);
608
+ }
609
+ };
610
+ }
611
+ };
612
+
613
+ // src/input.tsx
614
+ var import_react = __toESM(require("react"));
467
615
  var import_rxjs = require("rxjs");
616
+ function TextEditorInput({
617
+ ref,
618
+ onChange,
619
+ updateDelay = 0,
620
+ ...props
621
+ }) {
622
+ const inputRef = import_react.default.useRef(null);
623
+ (0, import_react.useEffect)(() => {
624
+ const controller = ref.current;
625
+ if (!controller) {
626
+ return;
627
+ }
628
+ const sub = controller.subject.pipe(
629
+ (0, import_rxjs.filter)((tr) => tr.docChanged),
630
+ (0, import_rxjs.debounceTime)(updateDelay)
631
+ ).subscribe(() => {
632
+ if (inputRef.current) {
633
+ inputRef.current.value = controller.value;
634
+ const event = new Event("input", { bubbles: true });
635
+ inputRef.current.dispatchEvent(event);
636
+ }
637
+ });
638
+ return () => {
639
+ sub.unsubscribe();
640
+ controller.view.destroy();
641
+ };
642
+ }, []);
643
+ return /* @__PURE__ */ import_react.default.createElement("input", { ...props, ref: inputRef, type: "hidden", onInput: onChange });
644
+ }
645
+
646
+ // src/text_editor_controller.tsx
647
+ var import_prosemirror_state5 = require("prosemirror-state");
648
+ var import_prosemirror_view4 = require("prosemirror-view");
649
+ var commands2 = __toESM(require("prosemirror-commands"));
650
+ var import_prosemirror_keymap = require("prosemirror-keymap");
651
+
652
+ // src/plugins/drag_and_drop.tsx
653
+ var import_prosemirror_state = require("prosemirror-state");
654
+ function dragAndDropPlugin({ attachFile }) {
655
+ return new import_prosemirror_state.Plugin({
656
+ props: {
657
+ handleDOMEvents: {
658
+ drop(view, event) {
659
+ if (!attachFile) {
660
+ return;
661
+ }
662
+ const files = event.dataTransfer?.files;
663
+ if (!files || files.length === 0) {
664
+ return;
665
+ }
666
+ event.preventDefault();
667
+ const pos = view.state.selection.$from.pos || view.posAtCoords({
668
+ left: event.clientX,
669
+ top: event.clientY
670
+ })?.pos || null;
671
+ if (pos === null) {
672
+ return;
673
+ }
674
+ const medias = Array.from(files).filter(
675
+ (file) => file.type.startsWith("image/") || file.type.startsWith("video/")
676
+ );
677
+ attachFile(view, medias);
678
+ return true;
679
+ }
680
+ }
681
+ }
682
+ });
683
+ }
684
+
685
+ // src/plugins/upload_placeholder.tsx
686
+ var import_prosemirror_state2 = require("prosemirror-state");
687
+ var import_prosemirror_view = require("prosemirror-view");
688
+ var uploadPlaceholderPlugin = new import_prosemirror_state2.Plugin({
689
+ state: {
690
+ init() {
691
+ return import_prosemirror_view.DecorationSet.empty;
692
+ },
693
+ apply(tr, set) {
694
+ set = set.map(tr.mapping, tr.doc);
695
+ const action = tr.getMeta(this);
696
+ if (action && action.add) {
697
+ const { type, width, height } = action.add;
698
+ const widget = document.createElement("div");
699
+ widget.className = "upload-placeholder";
700
+ widget.style.width = `100%`;
701
+ if (type.startsWith("image/") || type.startsWith("video/")) {
702
+ widget.style.aspectRatio = `${width} / ${height}`;
703
+ widget.style.maxWidth = `${width}px`;
704
+ } else {
705
+ widget.style.height = "80px";
706
+ }
707
+ const progress = document.createElement("div");
708
+ progress.className = "upload-progress";
709
+ widget.appendChild(progress);
710
+ const deco = import_prosemirror_view.Decoration.widget(action.add.pos, widget, {
711
+ id: action.add.id
712
+ });
713
+ set = set.add(tr.doc, [deco]);
714
+ } else if (action && action.progress) {
715
+ const found = set.find(
716
+ void 0,
717
+ void 0,
718
+ (spec) => spec.id === action.progress.id
719
+ );
720
+ if (found.length) {
721
+ const widget = found[0].type.toDOM;
722
+ const progress = widget.querySelector(".upload-progress");
723
+ if (progress) {
724
+ progress.innerHTML = `${Math.round(action.progress.progress)}%`;
725
+ }
726
+ }
727
+ } else if (action && action.remove) {
728
+ set = set.remove(
729
+ set.find(void 0, void 0, (spec) => spec.id === action.remove.id)
730
+ );
731
+ }
732
+ return set;
733
+ }
734
+ },
735
+ props: {
736
+ decorations(state) {
737
+ return this.getState(state);
738
+ }
739
+ }
740
+ });
741
+ var findPlaceholder = (state, id) => {
742
+ const decos = uploadPlaceholderPlugin.getState(state);
743
+ if (!decos) {
744
+ return null;
745
+ }
746
+ const found = decos.find(void 0, void 0, (spec) => spec.id === id);
747
+ return found.length ? found[0].from : null;
748
+ };
749
+
750
+ // src/plugins/placehoder.tsx
751
+ var import_prosemirror_model2 = require("prosemirror-model");
752
+ var import_prosemirror_state3 = require("prosemirror-state");
753
+ var import_prosemirror_view2 = require("prosemirror-view");
754
+ var getFirstChildDescendants = (view) => {
755
+ const nodes = [];
756
+ view.state.doc?.descendants((n) => {
757
+ nodes.push(n);
758
+ });
759
+ return nodes;
760
+ };
761
+ function placeholderPlugin(text) {
762
+ const update = (view) => {
763
+ const decos = uploadPlaceholderPlugin.getState(view.state);
764
+ 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) {
765
+ view.dom.removeAttribute("data-placeholder");
766
+ } else {
767
+ view.dom.setAttribute("data-placeholder", text);
768
+ }
769
+ };
770
+ return new import_prosemirror_state3.Plugin({
771
+ view(view) {
772
+ update(view);
773
+ return { update };
774
+ }
775
+ });
776
+ }
777
+
778
+ // src/text_editor_controller.tsx
779
+ var import_prosemirror_history2 = require("prosemirror-history");
780
+
781
+ // src/plugins/keymap.tsx
782
+ var import_prosemirror_state4 = require("prosemirror-state");
783
+ var import_prosemirror_history = require("prosemirror-history");
784
+ var import_prosemirror_commands = require("prosemirror-commands");
785
+ var import_prosemirror_schema_list2 = require("prosemirror-schema-list");
786
+ function buildKeymap(schema) {
787
+ const keys = {};
788
+ function bind(key, cmd) {
789
+ keys[key] = cmd;
790
+ }
791
+ bind("Mod-z", import_prosemirror_history.undo);
792
+ bind("Shift-Mod-z", import_prosemirror_history.redo);
793
+ bind("Mod-y", import_prosemirror_history.redo);
794
+ const li = schema.nodes.list_item;
795
+ bind(
796
+ "Enter",
797
+ (0, import_prosemirror_commands.chainCommands)((0, import_prosemirror_schema_list2.splitListItem)(li), (state, dispatch) => {
798
+ const { $head } = state.selection;
799
+ if ($head.parent.type === state.schema.nodes.paragraph) {
800
+ (0, import_prosemirror_commands.splitBlockAs)((n) => {
801
+ return {
802
+ type: n.type,
803
+ attrs: n.attrs
804
+ };
805
+ })(state, dispatch);
806
+ return true;
807
+ }
808
+ return false;
809
+ })
810
+ );
811
+ bind("ArrowDown", (state, dispatch) => {
812
+ const doc = state.doc;
813
+ const lastNode = doc.lastChild;
814
+ if (lastNode && lastNode.type.name !== "paragraph") {
815
+ const paragraphType = state.schema.nodes.paragraph;
816
+ let tr = state.tr;
817
+ const endPos = doc.content.size;
818
+ tr = tr.insert(endPos, paragraphType.create());
819
+ tr = tr.setSelection(import_prosemirror_state4.TextSelection.create(tr.doc, tr.doc.content.size));
820
+ if (dispatch) {
821
+ dispatch(tr);
822
+ }
823
+ return true;
824
+ }
825
+ return false;
826
+ });
827
+ return keys;
828
+ }
468
829
 
469
830
  // src/cn.ts
470
831
  function cn(...classes) {
@@ -473,7 +834,9 @@ function cn(...classes) {
473
834
 
474
835
  // src/attach_file.tsx
475
836
  var import_prosemirror_view3 = require("prosemirror-view");
476
- var base64ImageUploader = async (file) => {
837
+
838
+ // src/base64_file_uploader.ts
839
+ var base64FileUploader = async (file) => {
477
840
  const base64 = await new Promise((resolve, reject) => {
478
841
  const reader = new FileReader();
479
842
  reader.onload = () => {
@@ -487,10 +850,12 @@ var base64ImageUploader = async (file) => {
487
850
  alt: file.name
488
851
  };
489
852
  };
853
+
854
+ // src/attach_file.tsx
490
855
  function createAttachFile({
491
856
  schema,
492
857
  generateMetadata,
493
- uploadFile = base64ImageUploader
858
+ uploadFile = base64FileUploader
494
859
  }) {
495
860
  const attachEachFile = async (view, file, pos) => {
496
861
  const metadata = generateMetadata ? await generateMetadata(file) : {};
@@ -553,178 +918,230 @@ function createAttachFile({
553
918
  };
554
919
  }
555
920
 
556
- // src/text_editor.tsx
557
- function createTextEditor(options = {}) {
558
- const schema = createSchema();
921
+ // src/text_editor_controller.tsx
922
+ var import_prosemirror_model3 = require("prosemirror-model");
923
+ var import_rxjs2 = require("rxjs");
924
+ function createTextEditorController(container, schema, options, {
925
+ mode = "html",
926
+ state,
927
+ editor,
928
+ defaultValue,
929
+ updateDelay = 500,
930
+ placeholder
931
+ }) {
932
+ const subject = new import_rxjs2.Subject();
559
933
  const prosemirrorParser = import_prosemirror_model3.DOMParser.fromSchema(schema);
560
934
  const prosemirrorSerializer = import_prosemirror_model3.DOMSerializer.fromSchema(schema);
935
+ const wrapper = document.createElement("div");
936
+ const toInnerHTML = (value) => {
937
+ if (mode === "text") {
938
+ return value.split("\n").map((line) => `<p>${line}</p>`).join("");
939
+ }
940
+ return value;
941
+ };
942
+ wrapper.innerHTML = toInnerHTML(defaultValue ? String(defaultValue) : "");
561
943
  const attachFile = createAttachFile({
562
944
  schema,
563
945
  generateMetadata: options.attachFile?.generateMetadata,
564
946
  uploadFile: options.attachFile?.uploadFile
565
947
  });
948
+ const view = new import_prosemirror_view4.EditorView(container, {
949
+ ...editor,
950
+ attributes: (state2) => {
951
+ const propsAttributes = (() => {
952
+ if (typeof editor?.attributes === "function") {
953
+ return editor.attributes(state2);
954
+ }
955
+ return editor?.attributes;
956
+ })();
957
+ return {
958
+ ...propsAttributes,
959
+ class: cn(options?.className, propsAttributes?.class),
960
+ spellcheck: propsAttributes?.spellcheck || "false",
961
+ style: options.style || "width: 100%; height: inherit; outline: none;"
962
+ };
963
+ },
964
+ state: import_prosemirror_state5.EditorState.create({
965
+ ...state,
966
+ schema: state?.schema || schema,
967
+ doc: state?.doc || prosemirrorParser.parse(wrapper),
968
+ plugins: [
969
+ ...state?.plugins || [],
970
+ (0, import_prosemirror_history2.history)({
971
+ newGroupDelay: updateDelay
972
+ }),
973
+ (0, import_prosemirror_keymap.keymap)(buildKeymap(schema)),
974
+ (0, import_prosemirror_keymap.keymap)(commands2.baseKeymap),
975
+ uploadPlaceholderPlugin,
976
+ dragAndDropPlugin({
977
+ attachFile
978
+ }),
979
+ placeholder && placeholderPlugin(placeholder)
980
+ ].filter((e) => !!e)
981
+ }),
982
+ dispatchTransaction(tr) {
983
+ let result;
984
+ if (editor?.dispatchTransaction) {
985
+ result = editor.dispatchTransaction(tr);
986
+ } else {
987
+ view.updateState(view.state.apply(tr));
988
+ }
989
+ subject.next(tr);
990
+ return result;
991
+ }
992
+ });
993
+ function setValue(value) {
994
+ const wrap = document.createElement("div");
995
+ wrap.innerHTML = toInnerHTML(value);
996
+ const doc = prosemirrorParser.parse(wrap);
997
+ const tr = view.state.tr.replaceWith(
998
+ 0,
999
+ view.state.doc.content.size,
1000
+ doc.content
1001
+ );
1002
+ view.dispatch(tr);
1003
+ }
1004
+ function toHTML() {
1005
+ const fragment = prosemirrorSerializer.serializeFragment(
1006
+ view.state.doc.content
1007
+ );
1008
+ const container2 = document.createElement("div");
1009
+ container2.appendChild(fragment);
1010
+ return container2.innerHTML;
1011
+ }
1012
+ function toTextContent() {
1013
+ const state2 = view.state;
1014
+ return state2.doc.textBetween(0, state2.doc.content.size, "\n");
1015
+ }
1016
+ const textEditorCommands = createCommands(schema, view, {
1017
+ attachFile
1018
+ });
1019
+ const textEditorController = {
1020
+ schema,
1021
+ view,
1022
+ subject,
1023
+ set value(value) {
1024
+ setValue(value);
1025
+ },
1026
+ get value() {
1027
+ switch (mode) {
1028
+ case "text":
1029
+ return toTextContent();
1030
+ default:
1031
+ return toHTML();
1032
+ }
1033
+ },
1034
+ commands: textEditorCommands
1035
+ };
1036
+ return textEditorController;
1037
+ }
1038
+
1039
+ // src/create_text_editor.tsx
1040
+ function createTextEditor(options = {}) {
1041
+ const schema = createSchema();
566
1042
  function Component({
567
1043
  ref,
1044
+ className,
1045
+ autoFocus,
1046
+ onChange,
1047
+ mode,
568
1048
  state,
569
1049
  editor,
570
- mode = "html",
571
- container,
572
- autoFocus,
573
- name,
574
- placeholder,
575
- className,
576
1050
  defaultValue,
577
- onClick,
578
- onChange,
579
- updateDelay = 0,
1051
+ updateDelay,
1052
+ placeholder,
580
1053
  ...props
581
1054
  } = {}) {
582
- const containerRef = (0, import_react2.useRef)(null);
583
- const inputRef = (0, import_react2.useRef)(null);
584
- const controllerRef = (0, import_react2.useRef)(null);
585
- const subject = (0, import_react.useMemo)(() => new import_rxjs.Subject(), []);
586
- (0, import_react.useImperativeHandle)(ref, () => {
587
- const wrapper = document.createElement("div");
588
- const toInnerHTML = (value) => {
589
- if (mode === "html") {
590
- return value;
591
- }
592
- return value.split("\n").map((line) => `<p>${line}</p>`).join("");
593
- };
594
- wrapper.innerHTML = toInnerHTML(defaultValue ? String(defaultValue) : "");
595
- const view = new import_prosemirror_view4.EditorView(containerRef.current, {
596
- ...editor,
597
- attributes: (state2) => {
598
- const propsAttributes = (() => {
599
- if (typeof editor?.attributes === "function") {
600
- return editor.attributes(state2);
601
- }
602
- return editor?.attributes;
603
- })();
604
- return {
605
- ...propsAttributes,
606
- class: cn(propsAttributes?.class, className),
607
- spellcheck: propsAttributes?.spellcheck || "false"
608
- };
609
- },
610
- state: import_prosemirror_state4.EditorState.create({
611
- ...state,
612
- schema: state?.schema || schema,
613
- doc: state?.doc || prosemirrorParser.parse(wrapper),
614
- plugins: [
615
- ...state?.plugins || [],
616
- (0, import_prosemirror_history2.history)({
617
- newGroupDelay: updateDelay
618
- }),
619
- (0, import_prosemirror_keymap.keymap)(buildKeymap(schema)),
620
- (0, import_prosemirror_keymap.keymap)(import_prosemirror_commands2.baseKeymap),
621
- uploadPlaceholderPlugin,
622
- attachFile ? dragAndDropPlugin({
623
- attachFile
624
- }) : null,
625
- placeholder && placeholderPlugin(placeholder)
626
- ].filter((e) => !!e)
627
- }),
628
- dispatchTransaction(tr) {
629
- let result;
630
- if (editor?.dispatchTransaction) {
631
- result = editor.dispatchTransaction(tr);
632
- } else {
633
- view.updateState(view.state.apply(tr));
634
- }
635
- subject.next(tr);
636
- return result;
637
- }
638
- });
639
- function setValue(value) {
640
- const wrap = document.createElement("div");
641
- wrap.innerHTML = toInnerHTML(value);
642
- const doc = prosemirrorParser.parse(wrap);
643
- const tr = view.state.tr.replaceWith(
644
- 0,
645
- view.state.doc.content.size,
646
- doc.content
647
- );
648
- view.dispatch(tr);
649
- }
650
- function clear() {
651
- const tr = view.state.tr.replaceWith(
652
- 0,
653
- view.state.doc.content.size,
654
- schema.nodes.doc.createAndFill()
655
- );
656
- view.dispatch(tr);
657
- }
658
- function toHTML() {
659
- const fragment = prosemirrorSerializer.serializeFragment(
660
- view.state.doc.content
661
- );
662
- const container2 = document.createElement("div");
663
- container2.appendChild(fragment);
664
- return container2.innerHTML;
665
- }
666
- function toTextContent() {
667
- const state2 = view.state;
668
- return state2.doc.textBetween(0, state2.doc.content.size, "\n");
669
- }
670
- if (autoFocus) {
671
- view.focus();
672
- }
673
- const textEditorController = {
1055
+ const containerRef = (0, import_react3.useRef)(null);
1056
+ const controllerRef = (0, import_react3.useRef)(null);
1057
+ (0, import_react2.useImperativeHandle)(ref, () => {
1058
+ const container = containerRef.current;
1059
+ const textEditorController = createTextEditorController(
1060
+ container,
674
1061
  schema,
675
- view,
676
- subject,
677
- set value(value) {
678
- setValue(value);
679
- },
680
- get value() {
681
- switch (mode) {
682
- case "text":
683
- return toTextContent();
684
- default:
685
- return toHTML();
686
- }
687
- },
688
- clear
689
- };
1062
+ options,
1063
+ {
1064
+ mode,
1065
+ state,
1066
+ editor,
1067
+ defaultValue,
1068
+ updateDelay,
1069
+ placeholder
1070
+ }
1071
+ );
690
1072
  controllerRef.current = textEditorController;
691
1073
  return textEditorController;
692
1074
  });
693
- (0, import_react2.useEffect)(() => {
1075
+ (0, import_react3.useEffect)(() => {
694
1076
  const controller = controllerRef.current;
695
1077
  if (!controller) {
696
1078
  return;
697
1079
  }
698
- const sub = controller.subject.pipe(
699
- (0, import_rxjs.filter)((tr) => tr.docChanged),
700
- (0, import_rxjs.debounceTime)(updateDelay)
701
- ).subscribe(() => {
702
- if (inputRef.current) {
703
- inputRef.current.value = controller.value;
704
- const event = new Event("input", { bubbles: true });
705
- inputRef.current.dispatchEvent(event);
706
- }
707
- });
708
1080
  if (autoFocus) {
709
1081
  controller.view.focus();
710
1082
  }
711
- return () => {
712
- sub.unsubscribe();
713
- controller.view.destroy();
714
- };
715
1083
  }, []);
716
- return /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement("div", { ref: containerRef, className: container, ...props }), /* @__PURE__ */ import_react.default.createElement("input", { ref: inputRef, type: "hidden", name, onInput: onChange }));
1084
+ 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(
1085
+ TextEditorInput,
1086
+ {
1087
+ ref: controllerRef,
1088
+ updateDelay,
1089
+ defaultValue,
1090
+ onChange
1091
+ }
1092
+ ));
717
1093
  }
718
- return {
719
- schema,
720
- attachFile,
721
- Component
1094
+ return Component;
1095
+ }
1096
+
1097
+ // src/html.tsx
1098
+ var import_html_entities = require("html-entities");
1099
+ var import_react4 = __toESM(require("react"));
1100
+ function createInnerHTML(raw) {
1101
+ return raw.replace(/<\/p>/g, "<br></p>").replace(/(<p><br><\/p>)+$/g, "").replace(
1102
+ /<code class="language-(\w+)">([\s\S]*?)<\/code>/g,
1103
+ (_, lang, code) => {
1104
+ try {
1105
+ const highlighted = highlighter.highlight(code, {
1106
+ language: lang
1107
+ }).value;
1108
+ return `<code class="language-${lang}">${(0, import_html_entities.decode)(highlighted)}</code>`;
1109
+ } catch (e) {
1110
+ return `<code class="language-${lang}">${(0, import_html_entities.decode)(code)}</code>`;
1111
+ }
1112
+ }
1113
+ ).replace(
1114
+ /<a([^>]*target="_blank"[^>]*)>(.*?)<\/a>/g,
1115
+ (_, attrs, content) => {
1116
+ return `<a${attrs} rel="noopener noreferrer" target="_blank">${content}<svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M18.25 15.5a.75.75 0 0 1-.75-.75V7.56L7.28 17.78a.749.749 0 0 1-1.275-.326.749.749 0 0 1 .215-.734L16.44 6.5H9.25a.75.75 0 0 1 0-1.5h9a.75.75 0 0 1 .75.75v9a.75.75 0 0 1-.75.75Z"></path></svg></a>`;
1117
+ }
1118
+ );
1119
+ }
1120
+ function createTextEditorView(options = {}) {
1121
+ return function Component({
1122
+ className,
1123
+ dangerouslySetInnerHTML,
1124
+ ...props
1125
+ }) {
1126
+ return /* @__PURE__ */ import_react4.default.createElement(
1127
+ "div",
1128
+ {
1129
+ ...props,
1130
+ className: cn(options?.className, className),
1131
+ dangerouslySetInnerHTML: {
1132
+ __html: createInnerHTML(
1133
+ String(dangerouslySetInnerHTML?.__html || "")
1134
+ )
1135
+ }
1136
+ }
1137
+ );
722
1138
  };
723
1139
  }
724
1140
  // Annotate the CommonJS export names for ESM import in node:
725
1141
  0 && (module.exports = {
726
- base64ImageUploader,
727
1142
  createAttachFile,
1143
+ createInnerHTML,
728
1144
  createSchema,
729
- createTextEditor
1145
+ createTextEditor,
1146
+ createTextEditorView
730
1147
  });