react-headless-mde 1.0.0 → 1.0.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.
package/dist/cjs/index.js CHANGED
@@ -4,14 +4,218 @@ Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var react = require('react');
6
6
 
7
+ var CommandController = /** @class */ (function () {
8
+ function CommandController(textController) {
9
+ this.textController = textController;
10
+ }
11
+ CommandController.prototype.executeCommand = function (command, context) {
12
+ var _a;
13
+ var executeOptions = {
14
+ initialState: this.textController.getState(),
15
+ textApi: this.textController,
16
+ };
17
+ if (command.undo && ((_a = command.shouldUndo) === null || _a === void 0 ? void 0 : _a.call(command, executeOptions))) {
18
+ command.undo(executeOptions);
19
+ }
20
+ else {
21
+ command.execute(executeOptions, context);
22
+ }
23
+ };
24
+ return CommandController;
25
+ }());
26
+
27
+ var TextAreaTextController = /** @class */ (function () {
28
+ function TextAreaTextController(textAreaRef) {
29
+ this.textAreaRef = textAreaRef;
30
+ }
31
+ TextAreaTextController.prototype.getTextArea = function () {
32
+ var textArea = this.textAreaRef.current;
33
+ if (!textArea) {
34
+ throw new Error('TextAreaRef is not set');
35
+ }
36
+ return textArea;
37
+ };
38
+ TextAreaTextController.prototype.setSelection = function (selection) {
39
+ var textArea = this.getTextArea();
40
+ textArea.focus();
41
+ textArea.selectionStart = selection.start;
42
+ textArea.selectionEnd = selection.end;
43
+ return getStateFromTextArea(textArea);
44
+ };
45
+ TextAreaTextController.prototype.replaceSelection = function (text) {
46
+ var textArea = this.getTextArea();
47
+ insertText(textArea, text);
48
+ return getStateFromTextArea(textArea);
49
+ };
50
+ TextAreaTextController.prototype.replaceText = function (text, newText) {
51
+ var textArea = this.getTextArea();
52
+ textArea.value = textArea.value.replace(text, newText);
53
+ return getStateFromTextArea(textArea);
54
+ };
55
+ TextAreaTextController.prototype.getState = function () {
56
+ var textArea = this.getTextArea();
57
+ return getStateFromTextArea(textArea);
58
+ };
59
+ TextAreaTextController.prototype.moveCursorToTheEnd = function () {
60
+ var textArea = this.getTextArea();
61
+ textArea.focus();
62
+ textArea.selectionEnd = textArea.selectionStart = textArea.value.length;
63
+ return getStateFromTextArea(textArea);
64
+ };
65
+ return TextAreaTextController;
66
+ }());
67
+ function getStateFromTextArea(textArea) {
68
+ return {
69
+ selection: {
70
+ start: textArea.selectionStart,
71
+ end: textArea.selectionEnd,
72
+ },
73
+ text: textArea.value,
74
+ };
75
+ }
76
+ /**
77
+ * Inserts the given text at the cursor. If the element contains a selection, the selection
78
+ * will be replaced by the text.
79
+ * The MIT License
80
+ * Copyright (c) 2018 Dmitriy Kubyshkin
81
+ * Copied from https://github.com/grassator/insert-text-at-cursor
82
+ */
83
+ function insertText(input, text) {
84
+ var _a, _b, _c, _d;
85
+ // Most of the used APIs only work with the field selected
86
+ input.focus();
87
+ // IE 8-10
88
+ if (document.selection) {
89
+ var ieRange = document.selection.createRange();
90
+ ieRange.text = text;
91
+ // Move cursor after the inserted text
92
+ ieRange.collapse(false /* to the end */);
93
+ ieRange.select();
94
+ return;
95
+ }
96
+ // Webkit + Edge
97
+ var isSuccess = document.execCommand('insertText', false, text);
98
+ if (!isSuccess) {
99
+ var start = (_a = input.selectionStart) !== null && _a !== void 0 ? _a : 0;
100
+ var end = (_b = input.selectionEnd) !== null && _b !== void 0 ? _b : 0;
101
+ // Firefox (non-standard method)
102
+ if (typeof input.setRangeText === 'function') {
103
+ input.setRangeText(text);
104
+ }
105
+ else {
106
+ if (canManipulateViaTextNodes(input)) {
107
+ var textNode = document.createTextNode(text);
108
+ var node = input.firstChild;
109
+ // If textarea is empty, just insert the text
110
+ if (!node) {
111
+ input.appendChild(textNode);
112
+ }
113
+ else {
114
+ // Otherwise, we need to find a nodes for start and end
115
+ var offset = 0;
116
+ var startNode = null;
117
+ var endNode = null;
118
+ // To make a change we just need a Range, not a Selection
119
+ var range = document.createRange();
120
+ while (node && (startNode === null || endNode === null)) {
121
+ var nodeLength = (_d = (_c = node.nodeValue) === null || _c === void 0 ? void 0 : _c.length) !== null && _d !== void 0 ? _d : 0;
122
+ // if start of the selection falls into current node
123
+ if (start >= offset && start <= offset + nodeLength) {
124
+ range.setStart((startNode = node), start - offset);
125
+ }
126
+ // if end of the selection falls into current node
127
+ if (end >= offset && end <= offset + nodeLength) {
128
+ range.setEnd((endNode = node), end - offset);
129
+ }
130
+ offset += nodeLength;
131
+ node = node.nextSibling;
132
+ }
133
+ // If there is some text selected, remove it as we should replace it
134
+ if (start !== end) {
135
+ range.deleteContents();
136
+ }
137
+ // Finally insert a new node. The browser will automatically
138
+ // split start and end nodes into two if necessary
139
+ range.insertNode(textNode);
140
+ }
141
+ }
142
+ else {
143
+ // For the text input the only way is to replace the whole value :(
144
+ var value = input.value;
145
+ input.value = value.slice(0, start) + text + value.slice(end);
146
+ }
147
+ }
148
+ // Correct the cursor position to be at the end of the insertion
149
+ input.setSelectionRange(start + text.length, start + text.length);
150
+ // Notify any possible listeners of the change
151
+ var e = document.createEvent('UIEvent');
152
+ e.initEvent('input', true, false);
153
+ input.dispatchEvent(e);
154
+ }
155
+ }
7
156
  /**
8
- * A list of helpers for manipulating markdown text.
9
- * These helpers do not interface with a textarea. For that, see
157
+ * The MIT License
158
+ * Copyright (c) 2018 Dmitriy Kubyshkin
159
+ * Copied from https://github.com/grassator/insert-text-at-cursor
10
160
  */
161
+ function canManipulateViaTextNodes(input) {
162
+ if (input.nodeName !== 'TEXTAREA') {
163
+ return false;
164
+ }
165
+ var browserSupportsTextareaTextNodes;
166
+ if (typeof browserSupportsTextareaTextNodes === 'undefined') {
167
+ var textarea = document.createElement('textarea');
168
+ textarea.value = '1';
169
+ browserSupportsTextareaTextNodes = !!textarea.firstChild;
170
+ }
171
+ return browserSupportsTextareaTextNodes;
172
+ }
173
+
174
+ var CommandsService = /** @class */ (function () {
175
+ function CommandsService() {
176
+ this.commandController = null;
177
+ this.textController = null;
178
+ }
179
+ CommandsService.prototype.init = function (commandController, textController) {
180
+ this.commandController = commandController;
181
+ this.textController = textController;
182
+ };
183
+ CommandsService.prototype.createCommandFn = function (command) {
184
+ var _this = this;
185
+ return function (context) {
186
+ if (!_this.commandController) {
187
+ throw new Error('Cannot execute command. CommandsService is not initialized');
188
+ }
189
+ _this.commandController.executeCommand(command, context);
190
+ };
191
+ };
192
+ return CommandsService;
193
+ }());
194
+ var commandsService = new CommandsService();
195
+
196
+ function useTextAreaMarkdownEditor() {
197
+ var textAreaRef = react.useRef(null);
198
+ var textController = react.useMemo(function () {
199
+ var textAreaController = new TextAreaTextController(textAreaRef);
200
+ var commandController = new CommandController(textAreaController);
201
+ commandsService.init(commandController, textAreaController);
202
+ return textAreaController;
203
+ }, [textAreaRef]);
204
+ return {
205
+ textController: textController,
206
+ ref: textAreaRef,
207
+ };
208
+ }
209
+
210
+ // A list of helpers for manipulating Markdown text.
211
+ // These helpers do not interface with a textarea.
212
+ // Check if symbol is "space" or "new line"
213
+ // c is optional because we pass a char by index,
214
+ // and theoretically index can be outside the string range. See text[i - 1] and text[i].
215
+ var isWordDelimiter = function (c) { return !!c && (c === ' ' || c.charCodeAt(0) === 10); };
11
216
  function getSurroundingWord(text, position) {
12
- if (!text)
217
+ if (text.length === 0)
13
218
  throw Error("Argument 'text' should be truthy");
14
- var isWordDelimiter = function (c) { return c === ' ' || c.charCodeAt(0) === 10; };
15
219
  // leftIndex is initialized to 0 because if selection is 0, it won't even enter the iteration
16
220
  var start = 0;
17
221
  // rightIndex is initialized to text.length because if selection is equal to text.length it won't even enter the interation
@@ -32,24 +236,32 @@ function getSurroundingWord(text, position) {
32
236
  }
33
237
  return { start: start, end: end };
34
238
  }
35
- /**
36
- * If the cursor is inside a word and (selection.start === selection.end)
37
- * returns a new Selection where the whole word is selected
38
- * @param text
39
- * @param selection
40
- */
239
+ // If the cursor is inside a word and (selection.start === selection.end)
240
+ // returns a new Selection where the whole word is selected
41
241
  function selectWord(_a) {
42
242
  var text = _a.text, selection = _a.selection;
43
- if (text && text.length && selection.start === selection.end) {
243
+ if (text.length !== 0 && selection.start === selection.end) {
44
244
  // the user is pointing to a word
45
245
  return getSurroundingWord(text, selection.start);
46
246
  }
47
247
  return selection;
48
248
  }
49
- /**
50
- * Gets the number of line-breaks that would have to be inserted before the given 'startPosition'
51
- * to make sure there's an empty line between 'startPosition' and the previous text
52
- */
249
+ // If the cursor is inside a word (selection.start === selection.end) or there is a selection
250
+ // returns a new Selection where (selection.start === selection.end) but the position is after word
251
+ function selectAfterWord(_a) {
252
+ var text = _a.text, selection = _a.selection;
253
+ if (text.length !== 0) {
254
+ // the user is pointing to a word
255
+ var end = getSurroundingWord(text, selection.end).end;
256
+ return {
257
+ start: end,
258
+ end: end,
259
+ };
260
+ }
261
+ return selection;
262
+ }
263
+ // Gets the number of line-breaks that would have to be inserted before the given 'startPosition'
264
+ // to make sure there's an empty line between 'startPosition' and the previous text
53
265
  function getBreaksNeededForEmptyLineBefore(text, startPosition) {
54
266
  if (text === void 0) { text = ''; }
55
267
  if (startPosition === 0)
@@ -74,10 +286,8 @@ function getBreaksNeededForEmptyLineBefore(text, startPosition) {
74
286
  }
75
287
  return isInFirstLine ? 0 : neededBreaks;
76
288
  }
77
- /**
78
- * Gets the number of line-breaks that would have to be inserted after the given 'startPosition'
79
- * to make sure there's an empty line between 'startPosition' and the next text
80
- */
289
+ // Gets the number of line-breaks that would have to be inserted after the given 'startPosition'
290
+ // to make sure there's an empty line between 'startPosition' and the next text
81
291
  function getBreaksNeededForEmptyLineAfter(text, startPosition) {
82
292
  if (text === void 0) { text = ''; }
83
293
  if (startPosition === text.length - 1)
@@ -112,9 +322,7 @@ function getCharactersBeforeSelection(textState, characters) {
112
322
  function getCharactersAfterSelection(textState, characters) {
113
323
  return textState.text.slice(textState.selection.end, textState.selection.end + characters);
114
324
  }
115
- /**
116
- * Inserts insertionString before each line
117
- */
325
+ // Inserts insertionString before each line
118
326
  function insertBeforeEachLine(selectedText, insertBefore) {
119
327
  var lines = selectedText.split(/\n/);
120
328
  var insertionLength = 0;
@@ -139,6 +347,7 @@ var textHelpers = /*#__PURE__*/Object.freeze({
139
347
  __proto__: null,
140
348
  getSurroundingWord: getSurroundingWord,
141
349
  selectWord: selectWord,
350
+ selectAfterWord: selectAfterWord,
142
351
  getBreaksNeededForEmptyLineBefore: getBreaksNeededForEmptyLineBefore,
143
352
  getBreaksNeededForEmptyLineAfter: getBreaksNeededForEmptyLineAfter,
144
353
  getSelectedText: getSelectedText,
@@ -147,34 +356,6 @@ var textHelpers = /*#__PURE__*/Object.freeze({
147
356
  insertBeforeEachLine: insertBeforeEachLine
148
357
  });
149
358
 
150
- function setHeader(initialState, api, prefix) {
151
- // Adjust the selection to encompass the whole word if the caret is inside one
152
- var newSelectionRange = selectWord({
153
- text: initialState.text,
154
- selection: initialState.selection,
155
- });
156
- var state1 = api.setSelectionRange(newSelectionRange);
157
- // Add the prefix to the selection
158
- var state2 = api.replaceSelection("".concat(prefix).concat(getSelectedText(state1)));
159
- // Adjust the selection to not contain the prefix
160
- api.setSelectionRange({
161
- start: state2.selection.end - getSelectedText(state1).length,
162
- end: state2.selection.end,
163
- });
164
- }
165
-
166
- var headerHelpers = /*#__PURE__*/Object.freeze({
167
- __proto__: null,
168
- setHeader: setHeader
169
- });
170
-
171
- var headingLevel1Command = {
172
- execute: function (_a) {
173
- var initialState = _a.initialState, textApi = _a.textApi;
174
- setHeader(initialState, textApi, '# ');
175
- },
176
- };
177
-
178
359
  var boldCommand = {
179
360
  shouldUndo: function (options) {
180
361
  return (getCharactersBeforeSelection(options.initialState, 2) === '**' &&
@@ -187,11 +368,11 @@ var boldCommand = {
187
368
  text: initialState.text,
188
369
  selection: initialState.selection,
189
370
  });
190
- var state1 = textApi.setSelectionRange(newSelectionRange);
371
+ var state1 = textApi.setSelection(newSelectionRange);
191
372
  // Replaces the current selection with the bold mark up
192
373
  var state2 = textApi.replaceSelection("**".concat(getSelectedText(state1), "**"));
193
374
  // Adjust the selection to not contain the **
194
- textApi.setSelectionRange({
375
+ textApi.setSelection({
195
376
  start: state2.selection.end - 2 - getSelectedText(state1).length,
196
377
  end: state2.selection.end - 2,
197
378
  });
@@ -199,17 +380,18 @@ var boldCommand = {
199
380
  undo: function (_a) {
200
381
  var initialState = _a.initialState, textApi = _a.textApi;
201
382
  var text = getSelectedText(initialState);
202
- textApi.setSelectionRange({
383
+ textApi.setSelection({
203
384
  start: initialState.selection.start - 2,
204
385
  end: initialState.selection.end + 2,
205
386
  });
206
387
  textApi.replaceSelection(text);
207
- textApi.setSelectionRange({
388
+ textApi.setSelection({
208
389
  start: initialState.selection.start - 2,
209
390
  end: initialState.selection.end - 2,
210
391
  });
211
392
  },
212
393
  };
394
+ var bold = commandsService.createCommandFn(boldCommand);
213
395
 
214
396
  var italicCommand = {
215
397
  shouldUndo: function (options) {
@@ -223,11 +405,11 @@ var italicCommand = {
223
405
  text: initialState.text,
224
406
  selection: initialState.selection,
225
407
  });
226
- var state1 = textApi.setSelectionRange(newSelectionRange);
408
+ var state1 = textApi.setSelection(newSelectionRange);
227
409
  // Replaces the current selection with the italic mark up
228
410
  var state2 = textApi.replaceSelection("*".concat(getSelectedText(state1), "*"));
229
411
  // Adjust the selection to not contain the *
230
- textApi.setSelectionRange({
412
+ textApi.setSelection({
231
413
  start: state2.selection.end - 1 - getSelectedText(state1).length,
232
414
  end: state2.selection.end - 1,
233
415
  });
@@ -235,17 +417,18 @@ var italicCommand = {
235
417
  undo: function (_a) {
236
418
  var initialState = _a.initialState, textApi = _a.textApi;
237
419
  var text = getSelectedText(initialState);
238
- textApi.setSelectionRange({
420
+ textApi.setSelection({
239
421
  start: initialState.selection.start - 1,
240
422
  end: initialState.selection.end + 1,
241
423
  });
242
424
  textApi.replaceSelection(text);
243
- textApi.setSelectionRange({
425
+ textApi.setSelection({
244
426
  start: initialState.selection.start - 1,
245
427
  end: initialState.selection.end - 1,
246
428
  });
247
429
  },
248
430
  };
431
+ var italic = commandsService.createCommandFn(italicCommand);
249
432
 
250
433
  var strikethroughCommand = {
251
434
  execute: function (_a) {
@@ -255,16 +438,17 @@ var strikethroughCommand = {
255
438
  text: initialState.text,
256
439
  selection: initialState.selection,
257
440
  });
258
- var state1 = textApi.setSelectionRange(newSelectionRange);
441
+ var state1 = textApi.setSelection(newSelectionRange);
259
442
  // Replaces the current selection with the strikethrough mark up
260
443
  var state2 = textApi.replaceSelection("~~".concat(getSelectedText(state1), "~~"));
261
444
  // Adjust the selection to not contain the ~~
262
- textApi.setSelectionRange({
445
+ textApi.setSelection({
263
446
  start: state2.selection.end - 2 - getSelectedText(state1).length,
264
447
  end: state2.selection.end - 2,
265
448
  });
266
449
  },
267
450
  };
451
+ var strikethrough = commandsService.createCommandFn(strikethroughCommand);
268
452
 
269
453
  var linkCommand = {
270
454
  execute: function (_a) {
@@ -274,16 +458,17 @@ var linkCommand = {
274
458
  text: initialState.text,
275
459
  selection: initialState.selection,
276
460
  });
277
- var state1 = textApi.setSelectionRange(newSelectionRange);
461
+ var state1 = textApi.setSelection(newSelectionRange);
278
462
  // Replaces the current selection with the bold mark up
279
463
  var state2 = textApi.replaceSelection("[".concat(getSelectedText(state1), "](url)"));
280
464
  // Adjust the selection to not contain the **
281
- textApi.setSelectionRange({
465
+ textApi.setSelection({
282
466
  start: state2.selection.end - 6 - getSelectedText(state1).length,
283
467
  end: state2.selection.end - 6,
284
468
  });
285
469
  },
286
470
  };
471
+ var link = commandsService.createCommandFn(linkCommand);
287
472
 
288
473
  var quoteCommand = {
289
474
  execute: function (_a) {
@@ -293,7 +478,7 @@ var quoteCommand = {
293
478
  text: initialState.text,
294
479
  selection: initialState.selection,
295
480
  });
296
- var state1 = textApi.setSelectionRange(newSelectionRange);
481
+ var state1 = textApi.setSelection(newSelectionRange);
297
482
  var breaksBeforeCount = getBreaksNeededForEmptyLineBefore(state1.text, state1.selection.start);
298
483
  var breaksBefore = Array(breaksBeforeCount + 1).join('\n');
299
484
  var breaksAfterCount = getBreaksNeededForEmptyLineAfter(state1.text, state1.selection.end);
@@ -302,18 +487,19 @@ var quoteCommand = {
302
487
  textApi.replaceSelection("".concat(breaksBefore, "> ").concat(getSelectedText(state1)).concat(breaksAfter));
303
488
  var selectionStart = state1.selection.start + breaksBeforeCount + 2;
304
489
  var selectionEnd = selectionStart + getSelectedText(state1).length;
305
- textApi.setSelectionRange({
490
+ textApi.setSelection({
306
491
  start: selectionStart,
307
492
  end: selectionEnd,
308
493
  });
309
494
  },
310
495
  };
496
+ var quote = commandsService.createCommandFn(quoteCommand);
311
497
 
312
498
  var imageCommand = {
313
499
  execute: function (_a) {
314
500
  var initialState = _a.initialState, textApi = _a.textApi;
315
501
  // Replaces the current selection with the whole word selected
316
- var state1 = textApi.setSelectionRange(selectWord({
502
+ var state1 = textApi.setSelection(selectWord({
317
503
  text: initialState.text,
318
504
  selection: initialState.selection,
319
505
  }));
@@ -321,277 +507,13 @@ var imageCommand = {
321
507
  var imageTemplate = getSelectedText(state1) || 'https://example.com/your-image.png';
322
508
  textApi.replaceSelection("![](".concat(imageTemplate, ")"));
323
509
  // Adjust the selection to not contain the **
324
- textApi.setSelectionRange({
510
+ textApi.setSelection({
325
511
  start: state1.selection.start + 4,
326
512
  end: state1.selection.start + 4 + imageTemplate.length,
327
513
  });
328
514
  },
329
515
  };
330
-
331
- /******************************************************************************
332
- Copyright (c) Microsoft Corporation.
333
-
334
- Permission to use, copy, modify, and/or distribute this software for any
335
- purpose with or without fee is hereby granted.
336
-
337
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
338
- REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
339
- AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
340
- INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
341
- LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
342
- OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
343
- PERFORMANCE OF THIS SOFTWARE.
344
- ***************************************************************************** */
345
-
346
- function __awaiter(thisArg, _arguments, P, generator) {
347
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
348
- return new (P || (P = Promise))(function (resolve, reject) {
349
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
350
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
351
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
352
- step((generator = generator.apply(thisArg, _arguments || [])).next());
353
- });
354
- }
355
-
356
- function __generator(thisArg, body) {
357
- var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
358
- return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
359
- function verb(n) { return function (v) { return step([n, v]); }; }
360
- function step(op) {
361
- if (f) throw new TypeError("Generator is already executing.");
362
- while (g && (g = 0, op[0] && (_ = 0)), _) try {
363
- if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
364
- if (y = 0, t) op = [op[0] & 2, t.value];
365
- switch (op[0]) {
366
- case 0: case 1: t = op; break;
367
- case 4: _.label++; return { value: op[1], done: false };
368
- case 5: _.label++; y = op[1]; op = [0]; continue;
369
- case 7: op = _.ops.pop(); _.trys.pop(); continue;
370
- default:
371
- if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
372
- if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
373
- if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
374
- if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
375
- if (t[2]) _.ops.pop();
376
- _.trys.pop(); continue;
377
- }
378
- op = body.call(thisArg, _);
379
- } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
380
- if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
381
- }
382
- }
383
-
384
- var CommandController = /** @class */ (function () {
385
- function CommandController(textController, commandMap) {
386
- // Indicates whether there is a command currently executing
387
- this.isExecuting = false;
388
- this.textController = textController;
389
- this.commandMap = commandMap;
390
- }
391
- CommandController.prototype.executeCommand = function (commandName, context) {
392
- var _a;
393
- return __awaiter(this, void 0, void 0, function () {
394
- var command, executeOptions;
395
- return __generator(this, function (_b) {
396
- switch (_b.label) {
397
- case 0:
398
- if (this.isExecuting) {
399
- // The simplest thing to do is to ignore commands while
400
- // there is already a command executing.
401
- // The alternative would be to queue commands
402
- // but there is no guarantee that the state after one command executes will still be compatible
403
- // with the next one. In fact, it is likely not to be.
404
- return [2 /*return*/];
405
- }
406
- command = this.commandMap[commandName];
407
- if (!command) {
408
- throw new Error("Cannot execute command. Command not found: ".concat(commandName));
409
- }
410
- executeOptions = {
411
- initialState: this.textController.getState(),
412
- textApi: this.textController,
413
- };
414
- if (!(((_a = command.shouldUndo) === null || _a === void 0 ? void 0 : _a.call(command, executeOptions)) && (command === null || command === void 0 ? void 0 : command.undo))) return [3 /*break*/, 1];
415
- command.undo(executeOptions);
416
- return [3 /*break*/, 3];
417
- case 1: return [4 /*yield*/, command.execute(executeOptions)];
418
- case 2:
419
- _b.sent();
420
- _b.label = 3;
421
- case 3: return [2 /*return*/];
422
- }
423
- });
424
- });
425
- };
426
- return CommandController;
427
- }());
428
-
429
- var TextAreaTextController = /** @class */ (function () {
430
- function TextAreaTextController(textAreaRef) {
431
- this.textAreaRef = textAreaRef;
432
- }
433
- TextAreaTextController.prototype.replaceSelection = function (text) {
434
- var textArea = this.textAreaRef.current;
435
- if (!textArea) {
436
- throw new Error('TextAreaRef is not set');
437
- }
438
- insertText(textArea, text);
439
- return getStateFromTextArea(textArea);
440
- };
441
- TextAreaTextController.prototype.setSelectionRange = function (selection) {
442
- var textArea = this.textAreaRef.current;
443
- if (!textArea) {
444
- throw new Error('TextAreaRef is not set');
445
- }
446
- textArea.focus();
447
- textArea.selectionStart = selection.start;
448
- textArea.selectionEnd = selection.end;
449
- return getStateFromTextArea(textArea);
450
- };
451
- TextAreaTextController.prototype.getState = function () {
452
- var textArea = this.textAreaRef.current;
453
- if (!textArea) {
454
- throw new Error('TextAreaRef is not set');
455
- }
456
- return getStateFromTextArea(textArea);
457
- };
458
- return TextAreaTextController;
459
- }());
460
- function getStateFromTextArea(textArea) {
461
- return {
462
- selection: {
463
- start: textArea.selectionStart,
464
- end: textArea.selectionEnd,
465
- },
466
- text: textArea.value,
467
- };
468
- }
469
- /**
470
- * Inserts the given text at the cursor. If the element contains a selection, the selection
471
- * will be replaced by the text.
472
- * The MIT License
473
- * Copyright (c) 2018 Dmitriy Kubyshkin
474
- * Copied from https://github.com/grassator/insert-text-at-cursor
475
- */
476
- function insertText(input, text) {
477
- var _a;
478
- // Most of the used APIs only work with the field selected
479
- input.focus();
480
- // IE 8-10
481
- if (document.selection) {
482
- var ieRange = document.selection.createRange();
483
- ieRange.text = text;
484
- // Move cursor after the inserted text
485
- ieRange.collapse(false /* to the end */);
486
- ieRange.select();
487
- return;
488
- }
489
- // Webkit + Edge
490
- var isSuccess = document.execCommand('insertText', false, text);
491
- if (!isSuccess) {
492
- var start = input.selectionStart || 0;
493
- var end = input.selectionEnd || 0;
494
- // Firefox (non-standard method)
495
- if (typeof input.setRangeText === 'function') {
496
- input.setRangeText(text);
497
- }
498
- else {
499
- if (canManipulateViaTextNodes(input)) {
500
- var textNode = document.createTextNode(text);
501
- var node = input.firstChild;
502
- // If textarea is empty, just insert the text
503
- if (!node) {
504
- input.appendChild(textNode);
505
- }
506
- else {
507
- // Otherwise, we need to find a nodes for start and end
508
- var offset = 0;
509
- var startNode = null;
510
- var endNode = null;
511
- // To make a change we just need a Range, not a Selection
512
- var range = document.createRange();
513
- while (node && (startNode === null || endNode === null)) {
514
- var nodeLength = ((_a = node.nodeValue) === null || _a === void 0 ? void 0 : _a.length) || 0;
515
- // if start of the selection falls into current node
516
- if (start >= offset && start <= offset + nodeLength) {
517
- range.setStart((startNode = node), start - offset);
518
- }
519
- // if end of the selection falls into current node
520
- if (end >= offset && end <= offset + nodeLength) {
521
- range.setEnd((endNode = node), end - offset);
522
- }
523
- offset += nodeLength;
524
- node = node.nextSibling;
525
- }
526
- // If there is some text selected, remove it as we should replace it
527
- if (start !== end) {
528
- range.deleteContents();
529
- }
530
- // Finally insert a new node. The browser will automatically
531
- // split start and end nodes into two if necessary
532
- range.insertNode(textNode);
533
- }
534
- }
535
- else {
536
- // For the text input the only way is to replace the whole value :(
537
- var value = input.value;
538
- input.value = value.slice(0, start) + text + value.slice(end);
539
- }
540
- }
541
- // Correct the cursor position to be at the end of the insertion
542
- input.setSelectionRange(start + text.length, start + text.length);
543
- // Notify any possible listeners of the change
544
- var e = document.createEvent('UIEvent');
545
- e.initEvent('input', true, false);
546
- input.dispatchEvent(e);
547
- }
548
- }
549
- /**
550
- * The MIT License
551
- * Copyright (c) 2018 Dmitriy Kubyshkin
552
- * Copied from https://github.com/grassator/insert-text-at-cursor
553
- */
554
- function canManipulateViaTextNodes(input) {
555
- if (input.nodeName !== 'TEXTAREA') {
556
- return false;
557
- }
558
- var browserSupportsTextareaTextNodes;
559
- if (typeof browserSupportsTextareaTextNodes === 'undefined') {
560
- var textarea = document.createElement('textarea');
561
- textarea.value = '1';
562
- browserSupportsTextareaTextNodes = !!textarea.firstChild;
563
- }
564
- return browserSupportsTextareaTextNodes;
565
- }
566
-
567
- function makeList(state0, textController, insertBefore) {
568
- // Adjust the selection to encompass the whole word if the caret is inside one
569
- var newSelectionRange = selectWord({
570
- text: state0.text,
571
- selection: state0.selection,
572
- });
573
- var state1 = textController.setSelectionRange(newSelectionRange);
574
- var breaksBeforeCount = getBreaksNeededForEmptyLineBefore(state1.text, state1.selection.start);
575
- var breaksBefore = Array(breaksBeforeCount + 1).join('\n');
576
- var breaksAfterCount = getBreaksNeededForEmptyLineAfter(state1.text, state1.selection.end);
577
- var breaksAfter = Array(breaksAfterCount + 1).join('\n');
578
- var modifiedText = insertBeforeEachLine(getSelectedText(state1), insertBefore);
579
- textController.replaceSelection("".concat(breaksBefore).concat(modifiedText.modifiedText).concat(breaksAfter));
580
- // Specifically when the text has only one line, we can exclude the "- ", for example, from the selection
581
- var oneLinerOffset = getSelectedText(state1).indexOf('\n') === -1 ? modifiedText.insertionLength : 0;
582
- var selectionStart = state1.selection.start + breaksBeforeCount + oneLinerOffset;
583
- var selectionEnd = selectionStart + modifiedText.modifiedText.length - oneLinerOffset;
584
- // Adjust the selection to not contain the **
585
- textController.setSelectionRange({
586
- start: selectionStart,
587
- end: selectionEnd,
588
- });
589
- }
590
-
591
- var listHelpers = /*#__PURE__*/Object.freeze({
592
- __proto__: null,
593
- makeList: makeList
594
- });
516
+ var image = commandsService.createCommandFn(imageCommand);
595
517
 
596
518
  var codeCommand = {
597
519
  shouldUndo: function (options) {
@@ -605,11 +527,11 @@ var codeCommand = {
605
527
  text: initialState.text,
606
528
  selection: initialState.selection,
607
529
  });
608
- var state1 = textApi.setSelectionRange(newSelectionRange);
530
+ var state1 = textApi.setSelection(newSelectionRange);
609
531
  // Replaces the current selection with the italic mark up
610
532
  var state2 = textApi.replaceSelection("`".concat(getSelectedText(state1), "`"));
611
533
  // Adjust the selection to not contain the *
612
- textApi.setSelectionRange({
534
+ textApi.setSelection({
613
535
  start: state2.selection.end - 1 - getSelectedText(state1).length,
614
536
  end: state2.selection.end - 1,
615
537
  });
@@ -617,69 +539,83 @@ var codeCommand = {
617
539
  undo: function (_a) {
618
540
  var initialState = _a.initialState, textApi = _a.textApi;
619
541
  var text = getSelectedText(initialState);
620
- textApi.setSelectionRange({
542
+ textApi.setSelection({
621
543
  start: initialState.selection.start - 1,
622
544
  end: initialState.selection.end + 1,
623
545
  });
624
546
  textApi.replaceSelection(text);
625
- textApi.setSelectionRange({
547
+ textApi.setSelection({
626
548
  start: initialState.selection.start - 1,
627
549
  end: initialState.selection.end - 1,
628
550
  });
629
551
  },
630
552
  };
631
-
632
- function useTextAreaMarkdownEditor(options) {
633
- var textAreaRef = react.useRef(null);
634
- var textController = react.useMemo(function () {
635
- return new TextAreaTextController(textAreaRef);
636
- }, [textAreaRef]);
637
- var commandController = react.useMemo(function () { return new CommandController(textController, options.commandMap); }, [textAreaRef]);
638
- return {
639
- textController: textController,
640
- commandController: commandController,
641
- ref: textAreaRef,
642
- };
643
- }
553
+ var code = commandsService.createCommandFn(codeCommand);
644
554
 
645
555
  var codeBlockCommand = {
646
556
  execute: function (_a) {
647
557
  var textApi = _a.textApi, initialState = _a.initialState;
648
- return __awaiter(void 0, void 0, void 0, function () {
649
- var newSelectionRange, state1, selectionStart_1, selectionEnd_1, breaksBeforeCount, breaksBefore, breaksAfterCount, breaksAfter, selectionStart, selectionEnd;
650
- return __generator(this, function (_b) {
651
- newSelectionRange = selectWord({
652
- text: initialState.text,
653
- selection: initialState.selection,
654
- });
655
- state1 = textApi.setSelectionRange(newSelectionRange);
656
- // when there's no breaking line
657
- if (getSelectedText(state1).indexOf('\n') === -1) {
658
- textApi.replaceSelection("`".concat(getSelectedText(state1), "`"));
659
- selectionStart_1 = state1.selection.start + 1;
660
- selectionEnd_1 = selectionStart_1 + getSelectedText(state1).length;
661
- textApi.setSelectionRange({
662
- start: selectionStart_1,
663
- end: selectionEnd_1,
664
- });
665
- return [2 /*return*/];
666
- }
667
- breaksBeforeCount = getBreaksNeededForEmptyLineBefore(state1.text, state1.selection.start);
668
- breaksBefore = Array(breaksBeforeCount + 1).join('\n');
669
- breaksAfterCount = getBreaksNeededForEmptyLineAfter(state1.text, state1.selection.end);
670
- breaksAfter = Array(breaksAfterCount + 1).join('\n');
671
- textApi.replaceSelection("".concat(breaksBefore, "```\n").concat(getSelectedText(state1), "\n```").concat(breaksAfter));
672
- selectionStart = state1.selection.start + breaksBeforeCount + 4;
673
- selectionEnd = selectionStart + getSelectedText(state1).length;
674
- textApi.setSelectionRange({
675
- start: selectionStart,
676
- end: selectionEnd,
677
- });
678
- return [2 /*return*/];
558
+ // Adjust the selection to encompass the whole word if the caret is inside one
559
+ var newSelectionRange = selectWord({
560
+ text: initialState.text,
561
+ selection: initialState.selection,
562
+ });
563
+ var state1 = textApi.setSelection(newSelectionRange);
564
+ // when there's no breaking line
565
+ if (!getSelectedText(state1).includes('\n')) {
566
+ textApi.replaceSelection("`".concat(getSelectedText(state1), "`"));
567
+ // Adjust the selection to not contain the **
568
+ var selectionStart_1 = state1.selection.start + 1;
569
+ var selectionEnd_1 = selectionStart_1 + getSelectedText(state1).length;
570
+ textApi.setSelection({
571
+ start: selectionStart_1,
572
+ end: selectionEnd_1,
679
573
  });
574
+ return;
575
+ }
576
+ var breaksBeforeCount = getBreaksNeededForEmptyLineBefore(state1.text, state1.selection.start);
577
+ var breaksBefore = Array(breaksBeforeCount + 1).join('\n');
578
+ var breaksAfterCount = getBreaksNeededForEmptyLineAfter(state1.text, state1.selection.end);
579
+ var breaksAfter = Array(breaksAfterCount + 1).join('\n');
580
+ textApi.replaceSelection("".concat(breaksBefore, "```\n").concat(getSelectedText(state1), "\n```").concat(breaksAfter));
581
+ var selectionStart = state1.selection.start + breaksBeforeCount + 4;
582
+ var selectionEnd = selectionStart + getSelectedText(state1).length;
583
+ textApi.setSelection({
584
+ start: selectionStart,
585
+ end: selectionEnd,
680
586
  });
681
587
  },
682
588
  };
589
+ var codeBlock = commandsService.createCommandFn(codeBlockCommand);
590
+
591
+ function makeList(state0, textController, insertBefore) {
592
+ // Adjust the selection to encompass the whole word if the caret is inside one
593
+ var newSelectionRange = selectWord({
594
+ text: state0.text,
595
+ selection: state0.selection,
596
+ });
597
+ var state1 = textController.setSelection(newSelectionRange);
598
+ var breaksBeforeCount = getBreaksNeededForEmptyLineBefore(state1.text, state1.selection.start);
599
+ var breaksBefore = Array(breaksBeforeCount + 1).join('\n');
600
+ var breaksAfterCount = getBreaksNeededForEmptyLineAfter(state1.text, state1.selection.end);
601
+ var breaksAfter = Array(breaksAfterCount + 1).join('\n');
602
+ var modifiedText = insertBeforeEachLine(getSelectedText(state1), insertBefore);
603
+ textController.replaceSelection("".concat(breaksBefore).concat(modifiedText.modifiedText).concat(breaksAfter));
604
+ // Specifically when the text has only one line, we can exclude the "- ", for example, from the selection
605
+ var oneLinerOffset = !getSelectedText(state1).includes('\n') ? modifiedText.insertionLength : 0;
606
+ var selectionStart = state1.selection.start + breaksBeforeCount + oneLinerOffset;
607
+ var selectionEnd = selectionStart + modifiedText.modifiedText.length - oneLinerOffset;
608
+ // Adjust the selection to not contain the **
609
+ textController.setSelection({
610
+ start: selectionStart,
611
+ end: selectionEnd,
612
+ });
613
+ }
614
+
615
+ var listHelpers = /*#__PURE__*/Object.freeze({
616
+ __proto__: null,
617
+ makeList: makeList
618
+ });
683
619
 
684
620
  var checkedListCommand = {
685
621
  execute: function (_a) {
@@ -687,6 +623,7 @@ var checkedListCommand = {
687
623
  makeList(initialState, textApi, function () { return "- [ ] "; });
688
624
  },
689
625
  };
626
+ var checkedList = commandsService.createCommandFn(checkedListCommand);
690
627
 
691
628
  var orderedListCommand = {
692
629
  execute: function (_a) {
@@ -694,6 +631,7 @@ var orderedListCommand = {
694
631
  makeList(initialState, textApi, function (item, index) { return "".concat(index + 1, ". "); });
695
632
  },
696
633
  };
634
+ var orderedList = commandsService.createCommandFn(orderedListCommand);
697
635
 
698
636
  var unorderedListCommand = {
699
637
  execute: function (_a) {
@@ -701,6 +639,36 @@ var unorderedListCommand = {
701
639
  makeList(initialState, textApi, '- ');
702
640
  },
703
641
  };
642
+ var unorderedList = commandsService.createCommandFn(unorderedListCommand);
643
+
644
+ function setHeader(initialState, api, prefix) {
645
+ // Adjust the selection to encompass the whole word if the caret is inside one
646
+ var newSelectionRange = selectWord({
647
+ text: initialState.text,
648
+ selection: initialState.selection,
649
+ });
650
+ var state1 = api.setSelection(newSelectionRange);
651
+ // Add the prefix to the selection
652
+ var state2 = api.replaceSelection("".concat(prefix).concat(getSelectedText(state1)));
653
+ // Adjust the selection to not contain the prefix
654
+ api.setSelection({
655
+ start: state2.selection.end - getSelectedText(state1).length,
656
+ end: state2.selection.end,
657
+ });
658
+ }
659
+
660
+ var headerHelpers = /*#__PURE__*/Object.freeze({
661
+ __proto__: null,
662
+ setHeader: setHeader
663
+ });
664
+
665
+ var headingLevel1Command = {
666
+ execute: function (_a) {
667
+ var initialState = _a.initialState, textApi = _a.textApi;
668
+ setHeader(initialState, textApi, '# ');
669
+ },
670
+ };
671
+ var headingLevel1 = commandsService.createCommandFn(headingLevel1Command);
704
672
 
705
673
  var headingLevel2Command = {
706
674
  execute: function (_a) {
@@ -708,6 +676,7 @@ var headingLevel2Command = {
708
676
  setHeader(initialState, textApi, '## ');
709
677
  },
710
678
  };
679
+ var headingLevel2 = commandsService.createCommandFn(headingLevel2Command);
711
680
 
712
681
  var headingLevel3Command = {
713
682
  execute: function (_a) {
@@ -715,6 +684,7 @@ var headingLevel3Command = {
715
684
  setHeader(initialState, textApi, '### ');
716
685
  },
717
686
  };
687
+ var headingLevel3 = commandsService.createCommandFn(headingLevel3Command);
718
688
 
719
689
  var headingLevel4Command = {
720
690
  execute: function (_a) {
@@ -722,6 +692,7 @@ var headingLevel4Command = {
722
692
  setHeader(initialState, textApi, '#### ');
723
693
  },
724
694
  };
695
+ var headingLevel4 = commandsService.createCommandFn(headingLevel4Command);
725
696
 
726
697
  var headingLevel5Command = {
727
698
  execute: function (_a) {
@@ -729,6 +700,7 @@ var headingLevel5Command = {
729
700
  setHeader(initialState, textApi, '##### ');
730
701
  },
731
702
  };
703
+ var headingLevel5 = commandsService.createCommandFn(headingLevel5Command);
732
704
 
733
705
  var headingLevel6Command = {
734
706
  execute: function (_a) {
@@ -736,28 +708,68 @@ var headingLevel6Command = {
736
708
  setHeader(initialState, textApi, '###### ');
737
709
  },
738
710
  };
711
+ var headingLevel6 = commandsService.createCommandFn(headingLevel6Command);
712
+
713
+ // attachmentCommand does to following:
714
+ // 1. Sets cursor to the end of word
715
+ // 2. Inserts string "![Uploading test 1.jpg…]()"
716
+ // 3. When request is fulfilled replace "![Uploading test 1.jpg…]()" with real markdown url
717
+ // or add the markdown url to the end of text
718
+ // 4. If request is failed delete "![Uploading test 1.jpg…]()" and console.error
719
+ var attachmentCommand = {
720
+ execute: function (_a, _b) {
721
+ var initialState = _a.initialState, textApi = _a.textApi;
722
+ var fileName = _b.fileName, fileUrlPromise = _b.fileUrlPromise;
723
+ // Replaces the current selection with the empty selection
724
+ // and sets the cursor position to the end of the word
725
+ textApi.setSelection(selectAfterWord({
726
+ text: initialState.text,
727
+ selection: initialState.selection,
728
+ }));
729
+ var uploadingString = "![Uploading ".concat(fileName, "\u2026]()");
730
+ textApi.replaceSelection(' ' + uploadingString);
731
+ fileUrlPromise
732
+ .then(function (url) {
733
+ var fileLinkString = "![".concat(fileName, "\u2026](").concat(url, ")");
734
+ if (textApi.getState().text.includes(uploadingString)) {
735
+ textApi.replaceText(uploadingString, fileLinkString);
736
+ }
737
+ else {
738
+ textApi.moveCursorToTheEnd();
739
+ textApi.replaceSelection("\n".concat(fileLinkString));
740
+ }
741
+ })
742
+ .catch(function (error) {
743
+ if (textApi.getState().text.includes(uploadingString)) {
744
+ textApi.replaceText(uploadingString, '');
745
+ }
746
+ console.error(error);
747
+ });
748
+ },
749
+ };
750
+ var attachment = commandsService.createCommandFn(attachmentCommand);
739
751
 
740
- exports.CommandController = CommandController;
741
752
  exports.TextAreaTextController = TextAreaTextController;
742
- exports.boldCommand = boldCommand;
743
- exports.checkedListCommand = checkedListCommand;
744
- exports.codeBlockCommand = codeBlockCommand;
745
- exports.codeCommand = codeCommand;
753
+ exports.attachment = attachment;
754
+ exports.bold = bold;
755
+ exports.checkedList = checkedList;
756
+ exports.code = code;
757
+ exports.codeBlock = codeBlock;
746
758
  exports.headerHelpers = headerHelpers;
747
- exports.headingLevel1Command = headingLevel1Command;
748
- exports.headingLevel2Command = headingLevel2Command;
749
- exports.headingLevel3Command = headingLevel3Command;
750
- exports.headingLevel4Command = headingLevel4Command;
751
- exports.headingLevel5Command = headingLevel5Command;
752
- exports.headingLevel6Command = headingLevel6Command;
753
- exports.imageCommand = imageCommand;
754
- exports.italicCommand = italicCommand;
755
- exports.linkCommand = linkCommand;
759
+ exports.headingLevel1 = headingLevel1;
760
+ exports.headingLevel2 = headingLevel2;
761
+ exports.headingLevel3 = headingLevel3;
762
+ exports.headingLevel4 = headingLevel4;
763
+ exports.headingLevel5 = headingLevel5;
764
+ exports.headingLevel6 = headingLevel6;
765
+ exports.image = image;
766
+ exports.italic = italic;
767
+ exports.link = link;
756
768
  exports.listHelpers = listHelpers;
757
- exports.orderedListCommand = orderedListCommand;
758
- exports.quoteCommand = quoteCommand;
759
- exports.strikethroughCommand = strikethroughCommand;
769
+ exports.orderedList = orderedList;
770
+ exports.quote = quote;
771
+ exports.strikethrough = strikethrough;
760
772
  exports.textHelpers = textHelpers;
761
- exports.unorderedListCommand = unorderedListCommand;
773
+ exports.unorderedList = unorderedList;
762
774
  exports.useTextAreaMarkdownEditor = useTextAreaMarkdownEditor;
763
775
  //# sourceMappingURL=index.js.map