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