dn-react-text-editor 0.3.0 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -7,8 +7,6 @@ A rich text editor component for React built on ProseMirror.
7
7
  ```tsx
8
8
  import { TextEditor } from "dn-react-text-editor";
9
9
 
10
- const TextEditor = useTextEditor();
11
-
12
10
  function App() {
13
11
  return (
14
12
  <TextEditor
@@ -160,7 +160,12 @@ function createAttachFile({
160
160
  if (!node) {
161
161
  return;
162
162
  }
163
- view.dispatch(tr2.replaceWith($pos, $pos, node));
163
+ const current = view.state.doc.resolve($pos);
164
+ if (current.parentOffset === 0) {
165
+ view.dispatch(tr2.replaceWith($pos - 1, $pos, node));
166
+ } else {
167
+ view.dispatch(tr2.replaceWith($pos, $pos, node));
168
+ }
164
169
  } catch (e) {
165
170
  view.dispatch(tr.setMeta(uploadPlaceholderPlugin, { remove: { id } }));
166
171
  }
@@ -136,7 +136,12 @@ function createAttachFile({
136
136
  if (!node) {
137
137
  return;
138
138
  }
139
- view.dispatch(tr2.replaceWith($pos, $pos, node));
139
+ const current = view.state.doc.resolve($pos);
140
+ if (current.parentOffset === 0) {
141
+ view.dispatch(tr2.replaceWith($pos - 1, $pos, node));
142
+ } else {
143
+ view.dispatch(tr2.replaceWith($pos, $pos, node));
144
+ }
140
145
  } catch (e) {
141
146
  view.dispatch(tr.setMeta(uploadPlaceholderPlugin, { remove: { id } }));
142
147
  }
package/dist/html.js CHANGED
@@ -93,11 +93,12 @@ function createInnerHTML(raw) {
93
93
  return raw.replace(/<\/p>/g, "<br></p>").replace(/(<p><br><\/p>)+$/g, "").replace(
94
94
  /<code class="language-(\w+)">([\s\S]*?)<\/code>/g,
95
95
  (_, lang, code) => {
96
+ if (lang === "undefined") {
97
+ return `<code>${(0, import_html_entities.decode)(code)}</code>`;
98
+ }
96
99
  try {
97
- const highlighted = highlighter.highlight(code, {
98
- language: lang
99
- }).value;
100
- return `<code class="language-${lang}">${(0, import_html_entities.decode)(highlighted)}</code>`;
100
+ const { language, value } = highlighter.highlightAuto(code);
101
+ return `<code class="language-${language}">${(0, import_html_entities.decode)(value)}</code>`;
101
102
  } catch (e) {
102
103
  return `<code class="language-${lang}">${(0, import_html_entities.decode)(code)}</code>`;
103
104
  }
package/dist/html.mjs CHANGED
@@ -56,11 +56,12 @@ function createInnerHTML(raw) {
56
56
  return raw.replace(/<\/p>/g, "<br></p>").replace(/(<p><br><\/p>)+$/g, "").replace(
57
57
  /<code class="language-(\w+)">([\s\S]*?)<\/code>/g,
58
58
  (_, lang, code) => {
59
+ if (lang === "undefined") {
60
+ return `<code>${decode(code)}</code>`;
61
+ }
59
62
  try {
60
- const highlighted = highlighter.highlight(code, {
61
- language: lang
62
- }).value;
63
- return `<code class="language-${lang}">${decode(highlighted)}</code>`;
63
+ const { language, value } = highlighter.highlightAuto(code);
64
+ return `<code class="language-${language}">${decode(value)}</code>`;
64
65
  } catch (e) {
65
66
  return `<code class="language-${lang}">${decode(code)}</code>`;
66
67
  }
package/dist/index.d.mts CHANGED
@@ -1,8 +1,8 @@
1
- export { TextEditorProps, createTextEditor } from './create_text_editor.mjs';
1
+ export { TextEditor, TextEditorProps } from './text_editor.mjs';
2
2
  export { createSchema } from './schema.mjs';
3
3
  export { AttachFile, AttachFileOptions, GenerateMetadata, UploadFile, createAttachFile } from './attach_file.mjs';
4
4
  export { createInnerHTML, createTextEditorView } from './html.mjs';
5
- export { CreateTextEditorOptions, TextEditorController, TextEditorControllerProps } from './text_editor_controller.mjs';
5
+ export { ConfigTextEditorOptions, TextEditorController, TextEditorControllerProps, configTextEditorController } from './text_editor_controller.mjs';
6
6
  import 'react';
7
7
  import 'orderedmap';
8
8
  import 'prosemirror-model';
package/dist/index.d.ts CHANGED
@@ -1,8 +1,8 @@
1
- export { TextEditorProps, createTextEditor } from './create_text_editor.js';
1
+ export { TextEditor, TextEditorProps } from './text_editor.js';
2
2
  export { createSchema } from './schema.js';
3
3
  export { AttachFile, AttachFileOptions, GenerateMetadata, UploadFile, createAttachFile } from './attach_file.js';
4
4
  export { createInnerHTML, createTextEditorView } from './html.js';
5
- export { CreateTextEditorOptions, TextEditorController, TextEditorControllerProps } from './text_editor_controller.js';
5
+ export { ConfigTextEditorOptions, TextEditorController, TextEditorControllerProps, configTextEditorController } from './text_editor_controller.js';
6
6
  import 'react';
7
7
  import 'orderedmap';
8
8
  import 'prosemirror-model';
package/dist/index.js CHANGED
@@ -30,33 +30,29 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
+ TextEditor: () => TextEditor,
33
34
  TextEditorController: () => TextEditorController,
35
+ configTextEditorController: () => configTextEditorController,
34
36
  createAttachFile: () => createAttachFile,
35
37
  createInnerHTML: () => createInnerHTML,
36
38
  createSchema: () => createSchema,
37
- createTextEditor: () => createTextEditor,
38
39
  createTextEditorView: () => createTextEditorView
39
40
  });
40
41
  module.exports = __toCommonJS(index_exports);
41
42
 
42
- // src/create_text_editor.tsx
43
+ // src/text_editor.tsx
43
44
  var import_react2 = __toESM(require("react"));
44
45
  var import_react3 = require("react");
45
46
 
46
47
  // src/input.tsx
47
48
  var import_react = __toESM(require("react"));
48
49
  var import_rxjs = require("rxjs");
49
- function TextEditorInput({
50
- controller,
51
- onChange,
52
- updateDelay = 0,
53
- ...props
54
- }) {
50
+ function TextEditorInput({ controller, onChange, ...props }) {
55
51
  const inputRef = import_react.default.useRef(null);
56
52
  (0, import_react.useEffect)(() => {
57
53
  const sub = controller.subject.pipe(
58
54
  (0, import_rxjs.filter)((tr) => tr.docChanged),
59
- (0, import_rxjs.debounceTime)(updateDelay)
55
+ (0, import_rxjs.debounceTime)(controller.props.updateDelay || 0)
60
56
  ).subscribe(() => {
61
57
  if (inputRef.current) {
62
58
  inputRef.current.value = controller.value;
@@ -68,7 +64,16 @@ function TextEditorInput({
68
64
  sub.unsubscribe();
69
65
  };
70
66
  }, []);
71
- return /* @__PURE__ */ import_react.default.createElement("input", { ...props, ref: inputRef, type: "hidden", onInput: onChange });
67
+ return /* @__PURE__ */ import_react.default.createElement(
68
+ "input",
69
+ {
70
+ ...props,
71
+ ref: inputRef,
72
+ type: "hidden",
73
+ onInput: onChange,
74
+ defaultValue: controller.props.defaultValue
75
+ }
76
+ );
72
77
  }
73
78
 
74
79
  // src/text_editor_controller.tsx
@@ -219,23 +224,6 @@ function buildKeymap(schema) {
219
224
  bind("Mod-z", import_prosemirror_history.undo);
220
225
  bind("Shift-Mod-z", import_prosemirror_history.redo);
221
226
  bind("Mod-y", import_prosemirror_history.redo);
222
- const li = schema.nodes.list_item;
223
- bind(
224
- "Enter",
225
- (0, import_prosemirror_commands.chainCommands)((0, import_prosemirror_schema_list.splitListItem)(li), (state, dispatch) => {
226
- const { $head } = state.selection;
227
- if ($head.parent.type === state.schema.nodes.paragraph) {
228
- (0, import_prosemirror_commands.splitBlockAs)((n) => {
229
- return {
230
- type: n.type,
231
- attrs: n.attrs
232
- };
233
- })(state, dispatch);
234
- return true;
235
- }
236
- return false;
237
- })
238
- );
239
227
  bind("ArrowDown", (state, dispatch) => {
240
228
  const doc = state.doc;
241
229
  const lastNode = doc.lastChild;
@@ -252,6 +240,51 @@ function buildKeymap(schema) {
252
240
  }
253
241
  return false;
254
242
  });
243
+ const li = schema.nodes.list_item;
244
+ bind(
245
+ "Enter",
246
+ (0, import_prosemirror_commands.chainCommands)(
247
+ (0, import_prosemirror_schema_list.splitListItem)(li),
248
+ (state, dispatch) => {
249
+ const { $head } = state.selection;
250
+ if ($head.parent.type === state.schema.nodes.paragraph) {
251
+ (0, import_prosemirror_commands.splitBlockAs)((n) => {
252
+ return {
253
+ type: n.type,
254
+ attrs: n.attrs
255
+ };
256
+ })(state, dispatch);
257
+ return true;
258
+ }
259
+ return false;
260
+ },
261
+ (state, dispatch) => {
262
+ const { selection } = state;
263
+ const { $from, $to } = selection;
264
+ const lines = state.doc.textBetween($from.before(), $to.pos).split("\n");
265
+ const currentLine = lines[lines.length - 1];
266
+ const match = currentLine.match(/^(\s+).*$/);
267
+ if (match) {
268
+ if (dispatch) {
269
+ dispatch(state.tr.insertText("\n" + match[1], $from.pos));
270
+ }
271
+ return true;
272
+ }
273
+ return false;
274
+ }
275
+ )
276
+ );
277
+ bind("Tab", (state, dispatch) => {
278
+ const { selection } = state;
279
+ const { $from, $to } = selection;
280
+ if ($from.parent.type === schema.nodes.code_block) {
281
+ if (dispatch) {
282
+ dispatch(state.tr.insertText(" ", $from.pos, $to.pos));
283
+ }
284
+ return true;
285
+ }
286
+ return false;
287
+ });
255
288
  return keys;
256
289
  }
257
290
 
@@ -823,7 +856,12 @@ function createAttachFile({
823
856
  if (!node) {
824
857
  return;
825
858
  }
826
- view.dispatch(tr2.replaceWith($pos, $pos, node));
859
+ const current = view.state.doc.resolve($pos);
860
+ if (current.parentOffset === 0) {
861
+ view.dispatch(tr2.replaceWith($pos - 1, $pos, node));
862
+ } else {
863
+ view.dispatch(tr2.replaceWith($pos, $pos, node));
864
+ }
827
865
  } catch (e) {
828
866
  view.dispatch(tr.setMeta(uploadPlaceholderPlugin, { remove: { id } }));
829
867
  }
@@ -912,9 +950,9 @@ var createCommands = (schema, view, options = {}) => {
912
950
  // src/text_editor_controller.tsx
913
951
  var import_prosemirror_model3 = require("prosemirror-model");
914
952
  var import_rxjs2 = require("rxjs");
953
+ var import_prosemirror_highlightjs = require("prosemirror-highlightjs");
915
954
  var TextEditorController = class {
916
955
  schema;
917
- options;
918
956
  props;
919
957
  subject;
920
958
  view;
@@ -937,9 +975,8 @@ var TextEditorController = class {
937
975
  );
938
976
  this.view.dispatch(tr);
939
977
  }
940
- constructor(options = {}, props = {}) {
978
+ constructor(props = {}) {
941
979
  this.schema = createSchema();
942
- this.options = options;
943
980
  this.props = props;
944
981
  this.subject = new import_rxjs2.Subject();
945
982
  this.prosemirrorParser = import_prosemirror_model3.DOMParser.fromSchema(this.schema);
@@ -954,8 +991,8 @@ var TextEditorController = class {
954
991
  attachFile(files) {
955
992
  return createAttachFile({
956
993
  schema: this.schema,
957
- generateMetadata: this.options.attachFile?.generateMetadata,
958
- uploadFile: this.options.attachFile?.uploadFile
994
+ generateMetadata: this.props.attachFile?.generateMetadata,
995
+ uploadFile: this.props.attachFile?.uploadFile
959
996
  })(this.view, files);
960
997
  }
961
998
  bind(container) {
@@ -974,9 +1011,9 @@ var TextEditorController = class {
974
1011
  })();
975
1012
  return {
976
1013
  ...propsAttributes,
977
- class: cn(this.options?.className, propsAttributes?.class),
1014
+ class: cn(this.props.className, propsAttributes?.class),
978
1015
  spellcheck: propsAttributes?.spellcheck || "false",
979
- style: this.options.style || "width: 100%; height: inherit; outline: none;"
1016
+ style: this.props.style || "width: 100%; height: inherit; outline: none;"
980
1017
  };
981
1018
  },
982
1019
  state: import_prosemirror_state5.EditorState.create({
@@ -994,7 +1031,11 @@ var TextEditorController = class {
994
1031
  dragAndDropPlugin({
995
1032
  attachFile: (view, files) => this.attachFile(files)
996
1033
  }),
997
- this.props.placeholder && placeholderPlugin(this.props.placeholder)
1034
+ this.props.placeholder && placeholderPlugin(this.props.placeholder),
1035
+ (0, import_prosemirror_highlightjs.highlightPlugin)(highlighter, ["code_block"], (node) => {
1036
+ const auto = highlighter.highlightAuto(node.textContent);
1037
+ return auto.language || "";
1038
+ })
998
1039
  ].filter((e) => !!e)
999
1040
  }),
1000
1041
  dispatchTransaction: (tr) => {
@@ -1033,57 +1074,66 @@ var TextEditorController = class {
1033
1074
  this.view?.destroy();
1034
1075
  }
1035
1076
  };
1077
+ var configTextEditorController = (options = {}) => {
1078
+ return (props) => new TextEditorController({
1079
+ ...props,
1080
+ className: props.className || options.className,
1081
+ style: props.style || options.style,
1082
+ attachFile: props.attachFile || options.attachFile
1083
+ });
1084
+ };
1036
1085
 
1037
- // src/create_text_editor.tsx
1038
- function createTextEditor(options = {}) {
1039
- function Component({
1040
- controller: externalController,
1041
- className,
1042
- autoFocus,
1043
- onChange,
1044
- mode,
1045
- state,
1046
- editor,
1047
- defaultValue,
1048
- updateDelay,
1049
- placeholder,
1050
- ...props
1051
- } = {}) {
1052
- const containerRef = (0, import_react3.useRef)(null);
1053
- const innerController = (0, import_react2.useMemo)(
1054
- () => new TextEditorController(options, {
1055
- mode,
1056
- state,
1057
- editor,
1058
- autoFocus,
1059
- placeholder,
1060
- updateDelay,
1061
- defaultValue
1062
- }),
1063
- []
1064
- );
1065
- const controller = externalController || innerController;
1066
- (0, import_react3.useEffect)(() => {
1067
- const container = containerRef.current;
1068
- if (!container) {
1069
- return;
1070
- }
1071
- controller.bind(container);
1072
- return () => {
1073
- controller.dispose();
1074
- };
1075
- }, [controller]);
1076
- 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(
1077
- TextEditorInput,
1078
- {
1079
- controller,
1080
- updateDelay,
1081
- defaultValue,
1082
- onChange
1083
- }
1084
- ));
1085
- }
1086
- return Component;
1086
+ // src/text_editor.tsx
1087
+ function TextEditor({
1088
+ controller: externalController,
1089
+ name,
1090
+ className,
1091
+ autoFocus,
1092
+ onChange,
1093
+ mode,
1094
+ state,
1095
+ editor,
1096
+ defaultValue,
1097
+ updateDelay,
1098
+ placeholder,
1099
+ attachFile,
1100
+ style,
1101
+ ...props
1102
+ } = {}) {
1103
+ const containerRef = (0, import_react3.useRef)(null);
1104
+ const innerController = (0, import_react2.useMemo)(
1105
+ () => new TextEditorController({
1106
+ mode,
1107
+ state,
1108
+ editor,
1109
+ autoFocus,
1110
+ placeholder,
1111
+ updateDelay,
1112
+ defaultValue,
1113
+ attachFile,
1114
+ style
1115
+ }),
1116
+ []
1117
+ );
1118
+ const controller = externalController || innerController;
1119
+ (0, import_react3.useEffect)(() => {
1120
+ const container = containerRef.current;
1121
+ if (!container) {
1122
+ return;
1123
+ }
1124
+ controller.bind(container);
1125
+ return () => {
1126
+ controller.dispose();
1127
+ };
1128
+ }, [controller]);
1129
+ 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(
1130
+ TextEditorInput,
1131
+ {
1132
+ name,
1133
+ controller,
1134
+ onChange
1135
+ }
1136
+ ));
1087
1137
  }
1088
1138
 
1089
1139
  // src/html.tsx
@@ -1093,11 +1143,12 @@ function createInnerHTML(raw) {
1093
1143
  return raw.replace(/<\/p>/g, "<br></p>").replace(/(<p><br><\/p>)+$/g, "").replace(
1094
1144
  /<code class="language-(\w+)">([\s\S]*?)<\/code>/g,
1095
1145
  (_, lang, code) => {
1146
+ if (lang === "undefined") {
1147
+ return `<code>${(0, import_html_entities.decode)(code)}</code>`;
1148
+ }
1096
1149
  try {
1097
- const highlighted = highlighter.highlight(code, {
1098
- language: lang
1099
- }).value;
1100
- return `<code class="language-${lang}">${(0, import_html_entities.decode)(highlighted)}</code>`;
1150
+ const { language, value } = highlighter.highlightAuto(code);
1151
+ return `<code class="language-${language}">${(0, import_html_entities.decode)(value)}</code>`;
1101
1152
  } catch (e) {
1102
1153
  return `<code class="language-${lang}">${(0, import_html_entities.decode)(code)}</code>`;
1103
1154
  }
@@ -1131,10 +1182,11 @@ function createTextEditorView(options = {}) {
1131
1182
  }
1132
1183
  // Annotate the CommonJS export names for ESM import in node:
1133
1184
  0 && (module.exports = {
1185
+ TextEditor,
1134
1186
  TextEditorController,
1187
+ configTextEditorController,
1135
1188
  createAttachFile,
1136
1189
  createInnerHTML,
1137
1190
  createSchema,
1138
- createTextEditor,
1139
1191
  createTextEditorView
1140
1192
  });