react-headless-mde 0.0.1

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