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.
@@ -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/schema.tsx
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 import_prosemirror_model.Schema({
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 import_prosemirror_model.Schema({
525
- nodes: (0, import_prosemirror_schema_list.addListNodes)(customSchema.spec.nodes, "paragraph block*", "block"),
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/create_text_editor.tsx
532
- var import_rxjs3 = require("rxjs");
533
-
534
- // src/commands.tsx
535
- var commands = __toESM(require("prosemirror-commands"));
536
- var schemaList = __toESM(require("prosemirror-schema-list"));
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
- function createTextEditorController(container, schema, options, {
919
- mode = "html",
920
- state,
921
- editor,
922
- defaultValue,
923
- updateDelay = 500,
924
- placeholder
925
- }) {
926
- const subject = new import_rxjs2.Subject();
927
- const prosemirrorParser = import_prosemirror_model3.DOMParser.fromSchema(schema);
928
- const prosemirrorSerializer = import_prosemirror_model3.DOMSerializer.fromSchema(schema);
929
- const wrapper = document.createElement("div");
930
- const toInnerHTML = (value) => {
931
- if (mode === "text") {
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
- wrapper.innerHTML = toInnerHTML(defaultValue ? String(defaultValue) : "");
937
- const attachFile = createAttachFile({
938
- schema,
939
- generateMetadata: options.attachFile?.generateMetadata,
940
- uploadFile: options.attachFile?.uploadFile
941
- });
942
- const view = new import_prosemirror_view4.EditorView(container, {
943
- ...editor,
944
- attributes: (state2) => {
945
- const propsAttributes = (() => {
946
- if (typeof editor?.attributes === "function") {
947
- return editor.attributes(state2);
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
- return editor?.attributes;
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
- subject.next(tr);
984
- return result;
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
- function toHTML() {
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 container2 = document.createElement("div");
1003
- container2.appendChild(fragment);
1004
- return container2.innerHTML;
1012
+ const container = document.createElement("div");
1013
+ container.appendChild(fragment);
1014
+ return container.innerHTML;
1005
1015
  }
1006
- function toTextContent() {
1007
- const state2 = view.state;
1008
- return state2.doc.textBetween(0, state2.doc.content.size, "\n");
1016
+ toTextContent() {
1017
+ const state = this.view.state;
1018
+ return state.doc.textBetween(0, state.doc.content.size, "\n");
1009
1019
  }
1010
- const textEditorCommands = createCommands(schema, view, {
1011
- attachFile
1012
- });
1013
- const textEditorController = {
1014
- schema,
1015
- view,
1016
- subject,
1017
- set value(value) {
1018
- setValue(value);
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
- ref,
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 controllerRef = (0, import_react3.useRef)(null);
1051
- (0, import_react2.useImperativeHandle)(
1052
- ref || controllerRef,
1053
- () => {
1054
- const container = containerRef.current;
1055
- const textEditorController = createTextEditorController(
1056
- container,
1057
- schema,
1058
- options,
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 controller = controllerRef.current;
1075
- if (!controller) {
1060
+ const container = containerRef.current;
1061
+ if (!container) {
1076
1062
  return;
1077
1063
  }
1078
- if (autoFocus) {
1079
- controller.view.focus();
1080
- }
1064
+ controller.bind(container);
1081
1065
  return () => {
1082
- controller.view.destroy();
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
- ref: controllerRef,
1072
+ controller,
1089
1073
  updateDelay,
1090
1074
  defaultValue,
1091
1075
  onChange