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