react-headless-mde 1.0.3 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cjs/index.js CHANGED
@@ -4,75 +4,26 @@ 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) {
7
+ class CommandController {
8
+ constructor(textController, commandMap) {
9
9
  this.textController = textController;
10
+ this.commandMap = commandMap;
10
11
  }
11
- CommandController.prototype.executeCommand = function (command, context) {
12
+ executeCommand(commandName) {
12
13
  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);
14
+ const command = this.commandMap[commandName];
15
+ if (!command) {
16
+ throw new Error(`Cannot execute command. Command not found: ${commandName}`);
17
+ }
18
+ if (command.undo && ((_a = command.shouldUndo) === null || _a === void 0 ? void 0 : _a.call(command, this.textController))) {
19
+ command.undo(this.textController);
19
20
  }
20
21
  else {
21
- command.execute(executeOptions, context);
22
+ command.do(this.textController);
22
23
  }
23
- };
24
- return CommandController;
25
- }());
26
-
27
- var TextAreaTextController = /** @class */ (function () {
28
- function TextAreaTextController(textAreaRef) {
29
- this.textAreaRef = textAreaRef;
30
24
  }
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
25
  }
26
+
76
27
  /**
77
28
  * Inserts the given text at the cursor. If the element contains a selection, the selection
78
29
  * will be replaced by the text.
@@ -80,13 +31,13 @@ function getStateFromTextArea(textArea) {
80
31
  * Copyright (c) 2018 Dmitriy Kubyshkin
81
32
  * Copied from https://github.com/grassator/insert-text-at-cursor
82
33
  */
83
- function insertText(input, text) {
34
+ function insertToSelection(input, text) {
84
35
  var _a, _b, _c, _d;
85
36
  // Most of the used APIs only work with the field selected
86
37
  input.focus();
87
38
  // IE 8-10
88
39
  if (document.selection) {
89
- var ieRange = document.selection.createRange();
40
+ const ieRange = document.selection.createRange();
90
41
  ieRange.text = text;
91
42
  // Move cursor after the inserted text
92
43
  ieRange.collapse(false /* to the end */);
@@ -94,31 +45,31 @@ function insertText(input, text) {
94
45
  return;
95
46
  }
96
47
  // Webkit + Edge
97
- var isSuccess = document.execCommand('insertText', false, text);
48
+ const isSuccess = document.execCommand('insertText', false, text);
98
49
  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;
50
+ const start = (_a = input.selectionStart) !== null && _a !== void 0 ? _a : 0;
51
+ const end = (_b = input.selectionEnd) !== null && _b !== void 0 ? _b : 0;
101
52
  // Firefox (non-standard method)
102
53
  if (typeof input.setRangeText === 'function') {
103
54
  input.setRangeText(text);
104
55
  }
105
56
  else {
106
57
  if (canManipulateViaTextNodes(input)) {
107
- var textNode = document.createTextNode(text);
108
- var node = input.firstChild;
58
+ const textNode = document.createTextNode(text);
59
+ let node = input.firstChild;
109
60
  // If textarea is empty, just insert the text
110
61
  if (!node) {
111
62
  input.appendChild(textNode);
112
63
  }
113
64
  else {
114
65
  // Otherwise, we need to find a nodes for start and end
115
- var offset = 0;
116
- var startNode = null;
117
- var endNode = null;
66
+ let offset = 0;
67
+ let startNode = null;
68
+ let endNode = null;
118
69
  // To make a change we just need a Range, not a Selection
119
- var range = document.createRange();
70
+ const range = document.createRange();
120
71
  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;
72
+ const nodeLength = (_d = (_c = node.nodeValue) === null || _c === void 0 ? void 0 : _c.length) !== null && _d !== void 0 ? _d : 0;
122
73
  // if start of the selection falls into current node
123
74
  if (start >= offset && start <= offset + nodeLength) {
124
75
  range.setStart((startNode = node), start - offset);
@@ -141,14 +92,14 @@ function insertText(input, text) {
141
92
  }
142
93
  else {
143
94
  // For the text input the only way is to replace the whole value :(
144
- var value = input.value;
95
+ const value = input.value;
145
96
  input.value = value.slice(0, start) + text + value.slice(end);
146
97
  }
147
98
  }
148
99
  // Correct the cursor position to be at the end of the insertion
149
100
  input.setSelectionRange(start + text.length, start + text.length);
150
101
  // Notify any possible listeners of the change
151
- var e = document.createEvent('UIEvent');
102
+ const e = document.createEvent('UIEvent');
152
103
  e.initEvent('input', true, false);
153
104
  input.dispatchEvent(e);
154
105
  }
@@ -162,117 +113,77 @@ function canManipulateViaTextNodes(input) {
162
113
  if (input.nodeName !== 'TEXTAREA') {
163
114
  return false;
164
115
  }
165
- var browserSupportsTextareaTextNodes;
116
+ let browserSupportsTextareaTextNodes;
166
117
  if (typeof browserSupportsTextareaTextNodes === 'undefined') {
167
- var textarea = document.createElement('textarea');
118
+ const textarea = document.createElement('textarea');
168
119
  textarea.value = '1';
169
120
  browserSupportsTextareaTextNodes = !!textarea.firstChild;
170
121
  }
171
122
  return browserSupportsTextareaTextNodes;
172
123
  }
173
124
 
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
125
  // A list of helpers for manipulating Markdown text.
211
126
  // 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,
127
+ // Check if char is "space" or "new line".
128
+ // Char is optional because we pass a char by index,
214
129
  // 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); };
216
- function getSurroundingWord(text, position) {
130
+ const isWordDelimiter = (char) => !!char && (char === ' ' || char.charCodeAt(0) === 10);
131
+ const getSurroundingSelection = (text, position) => {
217
132
  if (text.length === 0)
218
133
  throw Error("Argument 'text' should be truthy");
219
134
  // leftIndex is initialized to 0 because if selection is 0, it won't even enter the iteration
220
- var start = 0;
135
+ let start = 0;
221
136
  // rightIndex is initialized to text.length because if selection is equal to text.length it won't even enter the interation
222
- var end = text.length;
137
+ let end = text.length;
223
138
  // iterate to the left
224
- for (var i = position; i - 1 > -1; i--) {
139
+ for (let i = position; i - 1 > -1; i--) {
225
140
  if (isWordDelimiter(text[i - 1])) {
226
141
  start = i;
227
142
  break;
228
143
  }
229
144
  }
230
145
  // iterate to the right
231
- for (var i = position; i < text.length; i++) {
146
+ for (let i = position; i < text.length; i++) {
232
147
  if (isWordDelimiter(text[i])) {
233
148
  end = i;
234
149
  break;
235
150
  }
236
151
  }
237
- return { start: start, end: end };
238
- }
152
+ return { start, end };
153
+ };
239
154
  // If the cursor is inside a word and (selection.start === selection.end)
240
155
  // returns a new Selection where the whole word is selected
241
- function selectWord(_a) {
242
- var text = _a.text, selection = _a.selection;
156
+ function getWordSelection({ text, selection }) {
243
157
  if (text.length !== 0 && selection.start === selection.end) {
244
158
  // the user is pointing to a word
245
- return getSurroundingWord(text, selection.start);
159
+ return getSurroundingSelection(text, selection.start);
246
160
  }
247
161
  return selection;
248
162
  }
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;
163
+ // Returns a new Selection where (selection.start === selection.end) but the position is after word
164
+ function selectAfterWord({ text, selection }) {
253
165
  if (text.length !== 0) {
254
166
  // the user is pointing to a word
255
- var end = getSurroundingWord(text, selection.end).end;
167
+ const { end } = getSurroundingSelection(text, selection.end);
256
168
  return {
257
169
  start: end,
258
- end: end,
170
+ end,
259
171
  };
260
172
  }
261
173
  return selection;
262
174
  }
263
175
  // Gets the number of line-breaks that would have to be inserted before the given 'startPosition'
264
176
  // to make sure there's an empty line between 'startPosition' and the previous text
265
- function getBreaksNeededForEmptyLineBefore(text, startPosition) {
266
- if (text === void 0) { text = ''; }
177
+ function getBreaksNeededForEmptyLineBefore(text = '', startPosition) {
267
178
  if (startPosition === 0)
268
179
  return 0;
269
- // rules:
180
+ // Rules:
270
181
  // - If we're in the first line, no breaks are needed
271
182
  // - Otherwise there must be 2 breaks before the previous character. Depending on how many breaks exist already, we
272
183
  // may need to insert 0, 1 or 2 breaks
273
- var neededBreaks = 2;
274
- var isInFirstLine = true;
275
- for (var i = startPosition - 1; i >= 0 && neededBreaks >= 0; i--) {
184
+ let neededBreaks = 2;
185
+ let isInFirstLine = true;
186
+ for (let i = startPosition - 1; i >= 0 && neededBreaks >= 0; i--) {
276
187
  switch (text.charCodeAt(i)) {
277
188
  case 32: // blank space
278
189
  continue;
@@ -288,17 +199,16 @@ function getBreaksNeededForEmptyLineBefore(text, startPosition) {
288
199
  }
289
200
  // Gets the number of line-breaks that would have to be inserted after the given 'startPosition'
290
201
  // to make sure there's an empty line between 'startPosition' and the next text
291
- function getBreaksNeededForEmptyLineAfter(text, startPosition) {
292
- if (text === void 0) { text = ''; }
202
+ function getBreaksNeededForEmptyLineAfter(text = '', startPosition) {
293
203
  if (startPosition === text.length - 1)
294
204
  return 0;
295
- // rules:
205
+ // Rules:
296
206
  // - If we're in the first line, no breaks are needed
297
207
  // - Otherwise there must be 2 breaks before the previous character. Depending on how many breaks exist already, we
298
208
  // may need to insert 0, 1 or 2 breaks
299
- var neededBreaks = 2;
300
- var isInLastLine = true;
301
- for (var i = startPosition; i < text.length && neededBreaks >= 0; i++) {
209
+ let neededBreaks = 2;
210
+ let isInLastLine = true;
211
+ for (let i = startPosition; i < text.length && neededBreaks >= 0; i++) {
302
212
  switch (text.charCodeAt(i)) {
303
213
  case 32:
304
214
  continue;
@@ -316,460 +226,410 @@ function getBreaksNeededForEmptyLineAfter(text, startPosition) {
316
226
  function getSelectedText(textSection) {
317
227
  return textSection.text.slice(textSection.selection.start, textSection.selection.end);
318
228
  }
319
- function getCharactersBeforeSelection(textState, characters) {
229
+ function getStringBeforeSelection(textState, characters) {
320
230
  return textState.text.slice(textState.selection.start - characters, textState.selection.start);
321
231
  }
322
- function getCharactersAfterSelection(textState, characters) {
232
+ function getStringAfterSelection(textState, characters) {
323
233
  return textState.text.slice(textState.selection.end, textState.selection.end + characters);
324
234
  }
325
235
  // Inserts insertionString before each line
326
236
  function insertBeforeEachLine(selectedText, insertBefore) {
327
- var lines = selectedText.split(/\n/);
328
- var insertionLength = 0;
329
- var modifiedText = lines
330
- .map(function (item, index) {
237
+ const lines = selectedText.split(/\n/);
238
+ let insertionLength = 0;
239
+ const modifiedText = lines
240
+ .map((item, index) => {
331
241
  if (typeof insertBefore === 'string') {
332
242
  insertionLength += insertBefore.length;
333
243
  return insertBefore + item;
334
244
  }
335
245
  else if (typeof insertBefore === 'function') {
336
- var insertionResult = insertBefore(item, index);
246
+ const insertionResult = insertBefore(item, index);
337
247
  insertionLength += insertionResult.length;
338
248
  return insertBefore(item, index) + item;
339
249
  }
340
250
  throw Error('insertion is expected to be either a string or a function');
341
251
  })
342
252
  .join('\n');
343
- return { modifiedText: modifiedText, insertionLength: insertionLength };
253
+ return { modifiedText, insertionLength };
344
254
  }
345
255
 
346
- var textHelpers = /*#__PURE__*/Object.freeze({
256
+ var selectionAndText = /*#__PURE__*/Object.freeze({
347
257
  __proto__: null,
348
- getSurroundingWord: getSurroundingWord,
349
- selectWord: selectWord,
258
+ getWordSelection: getWordSelection,
350
259
  selectAfterWord: selectAfterWord,
351
260
  getBreaksNeededForEmptyLineBefore: getBreaksNeededForEmptyLineBefore,
352
261
  getBreaksNeededForEmptyLineAfter: getBreaksNeededForEmptyLineAfter,
353
262
  getSelectedText: getSelectedText,
354
- getCharactersBeforeSelection: getCharactersBeforeSelection,
355
- getCharactersAfterSelection: getCharactersAfterSelection,
263
+ getStringBeforeSelection: getStringBeforeSelection,
264
+ getStringAfterSelection: getStringAfterSelection,
356
265
  insertBeforeEachLine: insertBeforeEachLine
357
266
  });
358
267
 
359
- var boldCommand = {
360
- shouldUndo: function (options) {
361
- return (getCharactersBeforeSelection(options.initialState, 2) === '**' &&
362
- getCharactersAfterSelection(options.initialState, 2) === '**');
363
- },
364
- execute: function (_a) {
365
- var initialState = _a.initialState, textApi = _a.textApi;
268
+ function getStateFromTextArea(textArea) {
269
+ return {
270
+ selection: {
271
+ start: textArea.selectionStart,
272
+ end: textArea.selectionEnd,
273
+ },
274
+ text: textArea.value,
275
+ };
276
+ }
277
+ class TextareaController {
278
+ constructor(textAreaRef) {
279
+ this.textAreaRef = textAreaRef;
280
+ }
281
+ get textArea() {
282
+ var _a;
283
+ const textArea = (_a = this.textAreaRef) === null || _a === void 0 ? void 0 : _a.current;
284
+ if (!textArea) {
285
+ throw new Error('No TextAreaRef');
286
+ }
287
+ return textArea;
288
+ }
289
+ selectWordByCursor() {
290
+ const initialState = this.getState();
366
291
  // Adjust the selection to encompass the whole word if the caret is inside one
367
- var newSelectionRange = selectWord({
292
+ const newSelectionRange = getWordSelection({
368
293
  text: initialState.text,
369
294
  selection: initialState.selection,
370
295
  });
371
- var state1 = textApi.setSelection(newSelectionRange);
372
- // Replaces the current selection with the bold mark up
373
- var state2 = textApi.replaceSelection("**".concat(getSelectedText(state1), "**"));
296
+ return this.setSelection(newSelectionRange);
297
+ }
298
+ setSelection({ start, end }) {
299
+ const textArea = this.textArea;
300
+ textArea.focus();
301
+ textArea.selectionStart = start;
302
+ textArea.selectionEnd = end;
303
+ return getStateFromTextArea(textArea);
304
+ }
305
+ replaceSelection(text) {
306
+ const textArea = this.textArea;
307
+ insertToSelection(textArea, text);
308
+ return getStateFromTextArea(textArea);
309
+ }
310
+ replaceText(searchString, replaceString) {
311
+ const textArea = this.textArea;
312
+ const startIndex = textArea.value.indexOf(searchString);
313
+ if (startIndex === -1)
314
+ return getStateFromTextArea(textArea);
315
+ this.setSelection({ start: startIndex, end: startIndex + searchString.length });
316
+ this.replaceSelection(replaceString);
317
+ return getStateFromTextArea(textArea);
318
+ }
319
+ wrapSelection(prefix, suffix) {
320
+ const state1 = this.getState();
321
+ // Replaces the current selection with new string
322
+ const state2 = this.replaceSelection(`${prefix}${getSelectedText(state1)}${suffix}`);
374
323
  // Adjust the selection to not contain the **
375
- textApi.setSelection({
376
- start: state2.selection.end - 2 - getSelectedText(state1).length,
377
- end: state2.selection.end - 2,
324
+ return this.setSelection({
325
+ start: state2.selection.end - prefix.length - getSelectedText(state1).length,
326
+ end: state2.selection.end - suffix.length,
378
327
  });
379
- },
380
- undo: function (_a) {
381
- var initialState = _a.initialState, textApi = _a.textApi;
382
- var text = getSelectedText(initialState);
383
- textApi.setSelection({
384
- start: initialState.selection.start - 2,
385
- end: initialState.selection.end + 2,
328
+ }
329
+ unwrapSelection(prefixLength, suffixLength) {
330
+ const initialState = this.getState();
331
+ const text = getSelectedText(initialState);
332
+ this.setSelection({
333
+ start: initialState.selection.start - prefixLength,
334
+ end: initialState.selection.end + suffixLength,
386
335
  });
387
- textApi.replaceSelection(text);
388
- textApi.setSelection({
389
- start: initialState.selection.start - 2,
390
- end: initialState.selection.end - 2,
336
+ this.replaceSelection(text);
337
+ return this.setSelection({
338
+ start: initialState.selection.start - prefixLength,
339
+ end: initialState.selection.end - suffixLength,
391
340
  });
341
+ }
342
+ getState() {
343
+ const textArea = this.textArea;
344
+ return getStateFromTextArea(textArea);
345
+ }
346
+ moveCursorToTheEnd() {
347
+ const textArea = this.textArea;
348
+ textArea.focus();
349
+ textArea.selectionEnd = textArea.selectionStart = textArea.value.length;
350
+ return getStateFromTextArea(textArea);
351
+ }
352
+ }
353
+
354
+ function useTextAreaMarkdownEditor(options) {
355
+ const textAreaRef = react.useRef(null);
356
+ return react.useMemo(() => {
357
+ const textController = new TextareaController(textAreaRef);
358
+ const commandController = new CommandController(textController, options.commandMap);
359
+ return {
360
+ ref: textAreaRef,
361
+ textController,
362
+ commandController,
363
+ };
364
+ }, [textAreaRef]);
365
+ }
366
+
367
+ function makeList(state0, textController, insertBefore) {
368
+ // Adjust the selection to encompass the whole word if the caret is inside one
369
+ const newSelectionRange = getWordSelection({
370
+ text: state0.text,
371
+ selection: state0.selection,
372
+ });
373
+ const state1 = textController.setSelection(newSelectionRange);
374
+ const breaksBeforeCount = getBreaksNeededForEmptyLineBefore(state1.text, state1.selection.start);
375
+ const breaksBefore = Array(breaksBeforeCount + 1).join('\n');
376
+ const breaksAfterCount = getBreaksNeededForEmptyLineAfter(state1.text, state1.selection.end);
377
+ const breaksAfter = Array(breaksAfterCount + 1).join('\n');
378
+ const modifiedText = insertBeforeEachLine(getSelectedText(state1), insertBefore);
379
+ textController.replaceSelection(`${breaksBefore}${modifiedText.modifiedText}${breaksAfter}`);
380
+ // Specifically when the text has only one line, we can exclude the "- ", for example, from the selection
381
+ const oneLinerOffset = !getSelectedText(state1).includes('\n') ? modifiedText.insertionLength : 0;
382
+ const selectionStart = state1.selection.start + breaksBeforeCount + oneLinerOffset;
383
+ const selectionEnd = selectionStart + modifiedText.modifiedText.length - oneLinerOffset;
384
+ // Adjust the selection to not contain the **
385
+ textController.setSelection({
386
+ start: selectionStart,
387
+ end: selectionEnd,
388
+ });
389
+ }
390
+
391
+ var list = /*#__PURE__*/Object.freeze({
392
+ __proto__: null,
393
+ makeList: makeList
394
+ });
395
+
396
+ function setHeader(initialState, api, prefix) {
397
+ // Adjust the selection to encompass the whole word if the caret is inside one
398
+ const newSelectionRange = getWordSelection({
399
+ text: initialState.text,
400
+ selection: initialState.selection,
401
+ });
402
+ const state1 = api.setSelection(newSelectionRange);
403
+ // Add the prefix to the selection
404
+ const state2 = api.replaceSelection(`${prefix}${getSelectedText(state1)}`);
405
+ // Adjust the selection to not contain the prefix
406
+ api.setSelection({
407
+ start: state2.selection.end - getSelectedText(state1).length,
408
+ end: state2.selection.end,
409
+ });
410
+ }
411
+
412
+ var header = /*#__PURE__*/Object.freeze({
413
+ __proto__: null,
414
+ setHeader: setHeader
415
+ });
416
+
417
+ const boldCommand = {
418
+ shouldUndo: textCtrl => {
419
+ const wordSelectionState = textCtrl.selectWordByCursor();
420
+ return (getStringBeforeSelection(wordSelectionState, 2) === '**' &&
421
+ getStringAfterSelection(wordSelectionState, 2) === '**');
422
+ },
423
+ do: textCtrl => {
424
+ textCtrl.wrapSelection('**', '**');
425
+ },
426
+ undo: textCtrl => {
427
+ textCtrl.unwrapSelection(2, 2);
392
428
  },
393
429
  };
394
- var bold = commandsService.createCommandFn(boldCommand);
395
430
 
396
- var italicCommand = {
397
- shouldUndo: function (options) {
398
- return (getCharactersBeforeSelection(options.initialState, 1) === '*' &&
399
- getCharactersAfterSelection(options.initialState, 1) === '*');
431
+ const italicCommand = {
432
+ shouldUndo: textCtrl => {
433
+ const wordSelectionState = textCtrl.selectWordByCursor();
434
+ return (getStringBeforeSelection(wordSelectionState, 1) === '*' && getStringAfterSelection(wordSelectionState, 1) === '*');
400
435
  },
401
- execute: function (_a) {
402
- var initialState = _a.initialState, textApi = _a.textApi;
403
- // Adjust the selection to encompass the whole word if the caret is inside one
404
- var newSelectionRange = selectWord({
405
- text: initialState.text,
406
- selection: initialState.selection,
407
- });
408
- var state1 = textApi.setSelection(newSelectionRange);
409
- // Replaces the current selection with the italic mark up
410
- var state2 = textApi.replaceSelection("*".concat(getSelectedText(state1), "*"));
411
- // Adjust the selection to not contain the *
412
- textApi.setSelection({
413
- start: state2.selection.end - 1 - getSelectedText(state1).length,
414
- end: state2.selection.end - 1,
415
- });
436
+ do(textCtrl) {
437
+ textCtrl.wrapSelection('*', '*');
416
438
  },
417
- undo: function (_a) {
418
- var initialState = _a.initialState, textApi = _a.textApi;
419
- var text = getSelectedText(initialState);
420
- textApi.setSelection({
421
- start: initialState.selection.start - 1,
422
- end: initialState.selection.end + 1,
423
- });
424
- textApi.replaceSelection(text);
425
- textApi.setSelection({
426
- start: initialState.selection.start - 1,
427
- end: initialState.selection.end - 1,
428
- });
439
+ undo(textCtrl) {
440
+ textCtrl.unwrapSelection(1, 1);
429
441
  },
430
442
  };
431
- var italic = commandsService.createCommandFn(italicCommand);
432
443
 
433
- var strikethroughCommand = {
434
- execute: function (_a) {
435
- var initialState = _a.initialState, textApi = _a.textApi;
436
- // Adjust the selection to encompass the whole word if the caret is inside one
437
- var newSelectionRange = selectWord({
438
- text: initialState.text,
439
- selection: initialState.selection,
440
- });
441
- var state1 = textApi.setSelection(newSelectionRange);
442
- // Replaces the current selection with the strikethrough mark up
443
- var state2 = textApi.replaceSelection("~~".concat(getSelectedText(state1), "~~"));
444
- // Adjust the selection to not contain the ~~
445
- textApi.setSelection({
446
- start: state2.selection.end - 2 - getSelectedText(state1).length,
447
- end: state2.selection.end - 2,
448
- });
444
+ const strikethroughCommand = {
445
+ shouldUndo(textCtrl) {
446
+ const wordSelectionState = textCtrl.selectWordByCursor();
447
+ return (getStringBeforeSelection(wordSelectionState, 2) === '~~' &&
448
+ getStringAfterSelection(wordSelectionState, 2) === '~~');
449
+ },
450
+ do(textCtrl) {
451
+ textCtrl.wrapSelection('~~', '~~');
452
+ },
453
+ undo(textCtrl) {
454
+ textCtrl.unwrapSelection(2, 2);
449
455
  },
450
456
  };
451
- var strikethrough = commandsService.createCommandFn(strikethroughCommand);
452
457
 
453
- var linkCommand = {
454
- execute: function (_a) {
455
- var initialState = _a.initialState, textApi = _a.textApi;
458
+ const linkCommand = {
459
+ do: textApi => {
456
460
  // Adjust the selection to encompass the whole word if the caret is inside one
457
- var newSelectionRange = selectWord({
458
- text: initialState.text,
459
- selection: initialState.selection,
460
- });
461
- var state1 = textApi.setSelection(newSelectionRange);
461
+ const wordSelectionState = textApi.selectWordByCursor();
462
462
  // Replaces the current selection with the bold mark up
463
- var state2 = textApi.replaceSelection("[".concat(getSelectedText(state1), "](url)"));
463
+ const state2 = textApi.replaceSelection(`[${getSelectedText(wordSelectionState)}](url)`);
464
464
  // Adjust the selection to not contain the **
465
465
  textApi.setSelection({
466
- start: state2.selection.end - 6 - getSelectedText(state1).length,
466
+ start: state2.selection.end - 6 - getSelectedText(wordSelectionState).length,
467
467
  end: state2.selection.end - 6,
468
468
  });
469
469
  },
470
470
  };
471
- var link = commandsService.createCommandFn(linkCommand);
472
471
 
473
- var quoteCommand = {
474
- execute: function (_a) {
475
- var initialState = _a.initialState, textApi = _a.textApi;
472
+ // Todo: try to rewrite with setHeader()
473
+ const quoteCommand = {
474
+ do: textApi => {
476
475
  // Adjust the selection to encompass the whole word if the caret is inside one
477
- var newSelectionRange = selectWord({
478
- text: initialState.text,
479
- selection: initialState.selection,
480
- });
481
- var state1 = textApi.setSelection(newSelectionRange);
482
- var breaksBeforeCount = getBreaksNeededForEmptyLineBefore(state1.text, state1.selection.start);
483
- var breaksBefore = Array(breaksBeforeCount + 1).join('\n');
484
- var breaksAfterCount = getBreaksNeededForEmptyLineAfter(state1.text, state1.selection.end);
485
- var breaksAfter = Array(breaksAfterCount + 1).join('\n');
476
+ const state = textApi.selectWordByCursor();
477
+ const breaksBeforeCount = getBreaksNeededForEmptyLineBefore(state.text, state.selection.start);
478
+ const breaksBefore = Array(breaksBeforeCount + 1).join('\n');
479
+ const breaksAfterCount = getBreaksNeededForEmptyLineAfter(state.text, state.selection.end);
480
+ const breaksAfter = Array(breaksAfterCount + 1).join('\n');
486
481
  // Replaces the current selection with the quote mark up
487
- textApi.replaceSelection("".concat(breaksBefore, "> ").concat(getSelectedText(state1)).concat(breaksAfter));
488
- var selectionStart = state1.selection.start + breaksBeforeCount + 2;
489
- var selectionEnd = selectionStart + getSelectedText(state1).length;
482
+ textApi.replaceSelection(`${breaksBefore}> ${getSelectedText(state)}${breaksAfter}`);
483
+ const selectionStart = state.selection.start + breaksBeforeCount + 2;
484
+ const selectionEnd = selectionStart + getSelectedText(state).length;
490
485
  textApi.setSelection({
491
486
  start: selectionStart,
492
487
  end: selectionEnd,
493
488
  });
494
489
  },
495
490
  };
496
- var quote = commandsService.createCommandFn(quoteCommand);
497
491
 
498
- var imageCommand = {
499
- execute: function (_a) {
500
- var initialState = _a.initialState, textApi = _a.textApi;
501
- // Replaces the current selection with the whole word selected
502
- var state1 = textApi.setSelection(selectWord({
503
- text: initialState.text,
504
- selection: initialState.selection,
505
- }));
506
- // Replaces the current selection with the image
507
- var imageTemplate = getSelectedText(state1) || 'https://example.com/your-image.png';
508
- textApi.replaceSelection("![](".concat(imageTemplate, ")"));
509
- // Adjust the selection to not contain the **
510
- textApi.setSelection({
511
- start: state1.selection.start + 4,
512
- end: state1.selection.start + 4 + imageTemplate.length,
513
- });
492
+ const codeCommand = {
493
+ shouldUndo: textCtrl => {
494
+ const wordSelectionState = textCtrl.selectWordByCursor();
495
+ return (getStringBeforeSelection(wordSelectionState, 1) === '`' && getStringAfterSelection(wordSelectionState, 1) === '`');
514
496
  },
515
- };
516
- var image = commandsService.createCommandFn(imageCommand);
517
-
518
- var codeCommand = {
519
- shouldUndo: function (options) {
520
- return (getCharactersBeforeSelection(options.initialState, 1) === '`' &&
521
- getCharactersAfterSelection(options.initialState, 1) === '`');
497
+ do(textCtrl) {
498
+ textCtrl.wrapSelection('`', '`');
522
499
  },
523
- execute: function (_a) {
524
- var initialState = _a.initialState, textApi = _a.textApi;
525
- // Adjust the selection to encompass the whole word if the caret is inside one
526
- var newSelectionRange = selectWord({
527
- text: initialState.text,
528
- selection: initialState.selection,
529
- });
530
- var state1 = textApi.setSelection(newSelectionRange);
531
- // Replaces the current selection with the italic mark up
532
- var state2 = textApi.replaceSelection("`".concat(getSelectedText(state1), "`"));
533
- // Adjust the selection to not contain the *
534
- textApi.setSelection({
535
- start: state2.selection.end - 1 - getSelectedText(state1).length,
536
- end: state2.selection.end - 1,
537
- });
538
- },
539
- undo: function (_a) {
540
- var initialState = _a.initialState, textApi = _a.textApi;
541
- var text = getSelectedText(initialState);
542
- textApi.setSelection({
543
- start: initialState.selection.start - 1,
544
- end: initialState.selection.end + 1,
545
- });
546
- textApi.replaceSelection(text);
547
- textApi.setSelection({
548
- start: initialState.selection.start - 1,
549
- end: initialState.selection.end - 1,
550
- });
500
+ undo(textCtrl) {
501
+ textCtrl.unwrapSelection(1, 1);
551
502
  },
552
503
  };
553
- var code = commandsService.createCommandFn(codeCommand);
554
504
 
555
- var codeBlockCommand = {
556
- execute: function (_a) {
557
- var textApi = _a.textApi, initialState = _a.initialState;
505
+ const codeBlockCommand = {
506
+ do: textApi => {
558
507
  // 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);
508
+ const state1 = textApi.selectWordByCursor();
564
509
  // when there's no breaking line
565
510
  if (!getSelectedText(state1).includes('\n')) {
566
- textApi.replaceSelection("`".concat(getSelectedText(state1), "`"));
511
+ textApi.replaceSelection(`\`${getSelectedText(state1)}\``);
567
512
  // Adjust the selection to not contain the **
568
- var selectionStart_1 = state1.selection.start + 1;
569
- var selectionEnd_1 = selectionStart_1 + getSelectedText(state1).length;
513
+ const selectionStart = state1.selection.start + 1;
514
+ const selectionEnd = selectionStart + getSelectedText(state1).length;
570
515
  textApi.setSelection({
571
- start: selectionStart_1,
572
- end: selectionEnd_1,
516
+ start: selectionStart,
517
+ end: selectionEnd,
573
518
  });
574
519
  return;
575
520
  }
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;
521
+ const breaksBeforeCount = getBreaksNeededForEmptyLineBefore(state1.text, state1.selection.start);
522
+ const breaksBefore = Array(breaksBeforeCount + 1).join('\n');
523
+ const breaksAfterCount = getBreaksNeededForEmptyLineAfter(state1.text, state1.selection.end);
524
+ const breaksAfter = Array(breaksAfterCount + 1).join('\n');
525
+ textApi.replaceSelection(`${breaksBefore}\`\`\`\n${getSelectedText(state1)}\n\`\`\`${breaksAfter}`);
526
+ const selectionStart = state1.selection.start + breaksBeforeCount + 4;
527
+ const selectionEnd = selectionStart + getSelectedText(state1).length;
583
528
  textApi.setSelection({
584
529
  start: selectionStart,
585
530
  end: selectionEnd,
586
531
  });
587
532
  },
588
533
  };
589
- var codeBlock = commandsService.createCommandFn(codeBlockCommand);
590
534
 
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
- });
619
-
620
- var checkedListCommand = {
621
- execute: function (_a) {
622
- var initialState = _a.initialState, textApi = _a.textApi;
623
- makeList(initialState, textApi, function () { return "- [ ] "; });
535
+ const checkedListCommand = {
536
+ do: textApi => {
537
+ const initialState = textApi.getState();
538
+ makeList(initialState, textApi, () => `- [ ] `);
624
539
  },
625
540
  };
626
- var checkedList = commandsService.createCommandFn(checkedListCommand);
627
541
 
628
- var orderedListCommand = {
629
- execute: function (_a) {
630
- var initialState = _a.initialState, textApi = _a.textApi;
631
- makeList(initialState, textApi, function (item, index) { return "".concat(index + 1, ". "); });
542
+ const orderedListCommand = {
543
+ do: textApi => {
544
+ const initialState = textApi.getState();
545
+ makeList(initialState, textApi, (item, index) => `${index + 1}. `);
632
546
  },
633
547
  };
634
- var orderedList = commandsService.createCommandFn(orderedListCommand);
635
548
 
636
- var unorderedListCommand = {
637
- execute: function (_a) {
638
- var initialState = _a.initialState, textApi = _a.textApi;
549
+ const unorderedListCommand = {
550
+ do: textApi => {
551
+ const initialState = textApi.getState();
639
552
  makeList(initialState, textApi, '- ');
640
553
  },
641
554
  };
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
555
 
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, '# ');
556
+ const imageCommand = {
557
+ do: textApi => {
558
+ // Replaces the current selection with the whole word selected
559
+ const wordSelectionState = textApi.selectWordByCursor();
560
+ // Replaces the current selection with the image
561
+ const imageTemplate = getSelectedText(wordSelectionState) || 'https://example.com/your-image.png';
562
+ textApi.replaceSelection(`![](${imageTemplate})`);
563
+ // Adjust the selection to not contain the **
564
+ textApi.setSelection({
565
+ start: wordSelectionState.selection.start + 4,
566
+ end: wordSelectionState.selection.start + 4 + imageTemplate.length,
567
+ });
669
568
  },
670
569
  };
671
- var headingLevel1 = commandsService.createCommandFn(headingLevel1Command);
672
570
 
673
- var headingLevel2Command = {
674
- execute: function (_a) {
675
- var initialState = _a.initialState, textApi = _a.textApi;
676
- setHeader(initialState, textApi, '## ');
571
+ const headingLevel1Command = {
572
+ do: textCtrl => {
573
+ const initialState = textCtrl.getState();
574
+ setHeader(initialState, textCtrl, '# ');
677
575
  },
678
576
  };
679
- var headingLevel2 = commandsService.createCommandFn(headingLevel2Command);
680
577
 
681
- var headingLevel3Command = {
682
- execute: function (_a) {
683
- var initialState = _a.initialState, textApi = _a.textApi;
684
- setHeader(initialState, textApi, '### ');
578
+ const headingLevel2Command = {
579
+ do: textCtrl => {
580
+ const initialState = textCtrl.getState();
581
+ setHeader(initialState, textCtrl, '## ');
685
582
  },
686
583
  };
687
- var headingLevel3 = commandsService.createCommandFn(headingLevel3Command);
688
584
 
689
- var headingLevel4Command = {
690
- execute: function (_a) {
691
- var initialState = _a.initialState, textApi = _a.textApi;
692
- setHeader(initialState, textApi, '#### ');
585
+ const headingLevel3Command = {
586
+ do: textCtrl => {
587
+ const initialState = textCtrl.getState();
588
+ setHeader(initialState, textCtrl, '### ');
693
589
  },
694
590
  };
695
- var headingLevel4 = commandsService.createCommandFn(headingLevel4Command);
696
591
 
697
- var headingLevel5Command = {
698
- execute: function (_a) {
699
- var initialState = _a.initialState, textApi = _a.textApi;
700
- setHeader(initialState, textApi, '##### ');
592
+ const headingLevel4Command = {
593
+ do: textCtrl => {
594
+ const initialState = textCtrl.getState();
595
+ setHeader(initialState, textCtrl, '#### ');
701
596
  },
702
597
  };
703
- var headingLevel5 = commandsService.createCommandFn(headingLevel5Command);
704
598
 
705
- var headingLevel6Command = {
706
- execute: function (_a) {
707
- var initialState = _a.initialState, textApi = _a.textApi;
708
- setHeader(initialState, textApi, '###### ');
599
+ const headingLevel5Command = {
600
+ do: textCtrl => {
601
+ const initialState = textCtrl.getState();
602
+ setHeader(initialState, textCtrl, '##### ');
709
603
  },
710
604
  };
711
- var headingLevel6 = commandsService.createCommandFn(headingLevel6Command);
712
605
 
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, "](").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
- });
606
+ const headingLevel6Command = {
607
+ do: textCtrl => {
608
+ const initialState = textCtrl.getState();
609
+ setHeader(initialState, textCtrl, '###### ');
748
610
  },
749
611
  };
750
- var attachment = commandsService.createCommandFn(attachmentCommand);
751
612
 
752
- exports.TextAreaTextController = TextAreaTextController;
753
- exports.attachment = attachment;
754
- exports.bold = bold;
755
- exports.checkedList = checkedList;
756
- exports.code = code;
757
- exports.codeBlock = codeBlock;
758
- exports.headerHelpers = headerHelpers;
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;
768
- exports.listHelpers = listHelpers;
769
- exports.orderedList = orderedList;
770
- exports.quote = quote;
771
- exports.strikethrough = strikethrough;
772
- exports.textHelpers = textHelpers;
773
- exports.unorderedList = unorderedList;
613
+ exports.TextareaController = TextareaController;
614
+ exports.boldCommand = boldCommand;
615
+ exports.checkedListCommand = checkedListCommand;
616
+ exports.codeBlockCommand = codeBlockCommand;
617
+ exports.codeCommand = codeCommand;
618
+ exports.headerHelpers = header;
619
+ exports.headingLevel1Command = headingLevel1Command;
620
+ exports.headingLevel2Command = headingLevel2Command;
621
+ exports.headingLevel3Command = headingLevel3Command;
622
+ exports.headingLevel4Command = headingLevel4Command;
623
+ exports.headingLevel5Command = headingLevel5Command;
624
+ exports.headingLevel6Command = headingLevel6Command;
625
+ exports.imageCommand = imageCommand;
626
+ exports.italicCommand = italicCommand;
627
+ exports.linkCommand = linkCommand;
628
+ exports.listHelpers = list;
629
+ exports.orderedListCommand = orderedListCommand;
630
+ exports.quoteCommand = quoteCommand;
631
+ exports.strikethroughCommand = strikethroughCommand;
632
+ exports.textHelpers = selectionAndText;
633
+ exports.unorderedListCommand = unorderedListCommand;
774
634
  exports.useTextAreaMarkdownEditor = useTextAreaMarkdownEditor;
775
635
  //# sourceMappingURL=index.js.map