@expensify/react-native-live-markdown 0.1.3 → 0.1.4
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/lib/commonjs/MarkdownTextInput.js +5 -55
- package/lib/commonjs/MarkdownTextInput.js.map +1 -1
- package/lib/commonjs/MarkdownTextInput.web.js +399 -9
- package/lib/commonjs/MarkdownTextInput.web.js.map +1 -1
- package/lib/commonjs/react-native-web.d.js +2 -0
- package/lib/commonjs/react-native-web.d.js.map +1 -0
- package/lib/commonjs/styleUtils.js +61 -0
- package/lib/commonjs/styleUtils.js.map +1 -0
- package/lib/commonjs/web/InputHistory.js +92 -0
- package/lib/commonjs/web/InputHistory.js.map +1 -0
- package/lib/commonjs/web/MarkdownTextInput.css +24 -0
- package/lib/commonjs/web/cursorUtils.js +90 -0
- package/lib/commonjs/web/cursorUtils.js.map +1 -0
- package/lib/commonjs/web/parserUtils.js +170 -0
- package/lib/commonjs/web/parserUtils.js.map +1 -0
- package/lib/module/MarkdownTextInput.js +3 -55
- package/lib/module/MarkdownTextInput.js.map +1 -1
- package/lib/module/MarkdownTextInput.web.js +399 -12
- package/lib/module/MarkdownTextInput.web.js.map +1 -1
- package/lib/module/react-native-web.d.js +2 -0
- package/lib/module/react-native-web.d.js.map +1 -0
- package/lib/module/styleUtils.js +56 -0
- package/lib/module/styleUtils.js.map +1 -0
- package/lib/module/web/InputHistory.js +85 -0
- package/lib/module/web/InputHistory.js.map +1 -0
- package/lib/module/web/MarkdownTextInput.css +24 -0
- package/lib/module/web/cursorUtils.js +83 -0
- package/lib/module/web/cursorUtils.js.map +1 -0
- package/lib/module/web/parserUtils.js +162 -0
- package/lib/module/web/parserUtils.js.map +1 -0
- package/lib/parser/react-native-live-markdown-parser.js +34 -0
- package/lib/typescript/src/MarkdownTextInput.d.ts +3 -6
- package/lib/typescript/src/MarkdownTextInput.d.ts.map +1 -1
- package/lib/typescript/src/MarkdownTextInput.web.d.ts +9 -2
- package/lib/typescript/src/MarkdownTextInput.web.d.ts.map +1 -1
- package/lib/typescript/src/styleUtils.d.ts +9 -0
- package/lib/typescript/src/styleUtils.d.ts.map +1 -0
- package/lib/typescript/src/web/InputHistory.d.ts +24 -0
- package/lib/typescript/src/web/InputHistory.d.ts.map +1 -0
- package/lib/typescript/src/web/cursorUtils.d.ts +8 -0
- package/lib/typescript/src/web/cursorUtils.d.ts.map +1 -0
- package/lib/typescript/src/web/parserUtils.d.ts +16 -0
- package/lib/typescript/src/web/parserUtils.d.ts.map +1 -0
- package/package.json +6 -3
- package/parser/react-native-live-markdown-parser.js +7 -7
- package/src/MarkdownTextInput.tsx +9 -69
- package/src/MarkdownTextInput.web.tsx +516 -16
- package/src/react-native-web.d.ts +1 -0
- package/src/styleUtils.ts +70 -0
- package/src/web/InputHistory.ts +114 -0
- package/src/web/MarkdownTextInput.css +24 -0
- package/src/web/cursorUtils.ts +87 -0
- package/src/web/parserUtils.ts +194 -0
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
type HistoryItem = {
|
|
2
|
+
text: string;
|
|
3
|
+
cursorPosition: number | null;
|
|
4
|
+
};
|
|
5
|
+
|
|
6
|
+
export default class InputHistory {
|
|
7
|
+
depth: number;
|
|
8
|
+
|
|
9
|
+
history: HistoryItem[];
|
|
10
|
+
|
|
11
|
+
historyIndex: number;
|
|
12
|
+
|
|
13
|
+
currentText: string | null = null;
|
|
14
|
+
|
|
15
|
+
timeout: NodeJS.Timeout | null = null;
|
|
16
|
+
|
|
17
|
+
debounceTime: number;
|
|
18
|
+
|
|
19
|
+
constructor(depth: number, debounceTime = 200) {
|
|
20
|
+
this.depth = depth;
|
|
21
|
+
this.history = [];
|
|
22
|
+
this.historyIndex = 0;
|
|
23
|
+
this.debounceTime = debounceTime;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
getCurrentItem(): HistoryItem | null {
|
|
27
|
+
return this.history[this.historyIndex] || null;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
setHistory(newHistory: HistoryItem[]): void {
|
|
31
|
+
this.history = newHistory.slice(newHistory.length - this.depth);
|
|
32
|
+
this.historyIndex = newHistory.length - 1;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
setHistoryIndex(index: number): void {
|
|
36
|
+
this.historyIndex = index;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
clear(): void {
|
|
40
|
+
this.history = [];
|
|
41
|
+
this.historyIndex = 0;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
debouncedAdd(text: string, cursorPosition: number): void {
|
|
45
|
+
this.currentText = text;
|
|
46
|
+
|
|
47
|
+
if (this.timeout) {
|
|
48
|
+
clearTimeout(this.timeout);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
this.timeout = setTimeout(() => {
|
|
52
|
+
if (this.currentText == null) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
this.add(this.currentText, cursorPosition);
|
|
56
|
+
this.currentText = null;
|
|
57
|
+
}, this.debounceTime);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
add(text: string, cursorPosition: number): void {
|
|
61
|
+
if (this.history.length > 0) {
|
|
62
|
+
const lastItem = this.history[this.history.length - 1];
|
|
63
|
+
if (lastItem && text === lastItem.text) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (this.historyIndex < this.history.length - 1) {
|
|
69
|
+
this.history.splice(this.historyIndex + 1);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
this.history.push({text, cursorPosition});
|
|
73
|
+
if (this.history.length > this.depth) {
|
|
74
|
+
this.history.shift();
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
this.historyIndex = this.history.length - 1;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
undo(): HistoryItem | null {
|
|
81
|
+
if (this.currentText !== null && this.timeout) {
|
|
82
|
+
clearTimeout(this.timeout);
|
|
83
|
+
return this.history[this.history.length - 1] || null;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (this.history.length === 0 || this.historyIndex - 1 < 0) {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (this.historyIndex > 0) {
|
|
91
|
+
this.historyIndex -= 1;
|
|
92
|
+
}
|
|
93
|
+
return this.history[this.historyIndex] || null;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
redo(): HistoryItem | null {
|
|
97
|
+
if (this.currentText !== null && this.timeout) {
|
|
98
|
+
clearTimeout(this.timeout);
|
|
99
|
+
return this.history[this.history.length - 1] || null;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (this.history.length === 0 || this.historyIndex + 1 > this.history.length) {
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (this.historyIndex < this.history.length - 1) {
|
|
107
|
+
this.historyIndex += 1;
|
|
108
|
+
} else {
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return this.history[this.historyIndex] || null;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
.react-native-live-markdown-input-singleline {
|
|
2
|
+
white-space: nowrap;
|
|
3
|
+
overflow: auto;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
.react-native-live-markdown-input-singleline::-webkit-scrollbar {
|
|
7
|
+
display: none;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.react-native-live-markdown-input-singleline br {
|
|
11
|
+
display: none;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.react-native-live-markdown-input-singleline * {
|
|
15
|
+
display: inline;
|
|
16
|
+
white-space: nowrap;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.react-native-live-markdown-input-singleline:empty::before,
|
|
20
|
+
.react-native-live-markdown-input-multiline:empty::before {
|
|
21
|
+
pointer-events: none;
|
|
22
|
+
display: block; /* For Firefox */
|
|
23
|
+
content: attr(placeholder);
|
|
24
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
function createRange(node: HTMLElement, targetPosition: number, ignoreNewLines = false) {
|
|
2
|
+
const range = document.createRange();
|
|
3
|
+
range.selectNode(node);
|
|
4
|
+
|
|
5
|
+
let pos = 0;
|
|
6
|
+
const stack: Node[] = [node];
|
|
7
|
+
while (stack.length > 0) {
|
|
8
|
+
const current = stack.pop();
|
|
9
|
+
if (!current) {
|
|
10
|
+
break;
|
|
11
|
+
}
|
|
12
|
+
if (current.nodeType === Node.TEXT_NODE || current.nodeName === 'BR') {
|
|
13
|
+
const textContentLength = current.textContent ? current.textContent.length : 0;
|
|
14
|
+
const len = current.nodeName === 'BR' ? 1 : textContentLength;
|
|
15
|
+
if (pos + len >= targetPosition) {
|
|
16
|
+
if (current.nodeName === 'BR') {
|
|
17
|
+
range.setStartAfter(current);
|
|
18
|
+
(current as HTMLElement).scrollIntoView();
|
|
19
|
+
} else {
|
|
20
|
+
range.setStart(current, targetPosition - pos);
|
|
21
|
+
}
|
|
22
|
+
return range;
|
|
23
|
+
}
|
|
24
|
+
pos += len;
|
|
25
|
+
} else if (current.childNodes && current.childNodes.length > 0) {
|
|
26
|
+
for (let i = current.childNodes.length - 1; i >= 0; i--) {
|
|
27
|
+
const currentNode = current.childNodes[i];
|
|
28
|
+
if (currentNode && (!ignoreNewLines || (ignoreNewLines && currentNode.nodeName !== 'BR'))) {
|
|
29
|
+
stack.push(currentNode);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
range.setStart(node, node.childNodes.length);
|
|
36
|
+
return range;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function setCursorPosition(target: HTMLElement, targetPosition: number, ignoreNewLines = false) {
|
|
40
|
+
const range = createRange(target, targetPosition, ignoreNewLines);
|
|
41
|
+
const selection = window.getSelection();
|
|
42
|
+
if (selection) {
|
|
43
|
+
range.collapse(true);
|
|
44
|
+
selection.removeAllRanges();
|
|
45
|
+
selection.addRange(range);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function moveCursorToEnd(target: HTMLElement) {
|
|
50
|
+
const range = document.createRange();
|
|
51
|
+
const selection = window.getSelection();
|
|
52
|
+
if (selection) {
|
|
53
|
+
range.setStart(target, target.childNodes.length);
|
|
54
|
+
range.collapse(true);
|
|
55
|
+
selection.removeAllRanges();
|
|
56
|
+
selection.addRange(range);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function getIndexedPosition(target: HTMLElement, range: Range, isStart: boolean) {
|
|
61
|
+
const marker = document.createTextNode('\0');
|
|
62
|
+
const rangeClone = range.cloneRange();
|
|
63
|
+
|
|
64
|
+
rangeClone.collapse(isStart);
|
|
65
|
+
|
|
66
|
+
rangeClone.insertNode(marker);
|
|
67
|
+
const position = target.innerText.indexOf('\0');
|
|
68
|
+
if (marker.parentNode) {
|
|
69
|
+
marker.parentNode.removeChild(marker);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return position;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function getCurrentCursorPosition(target: HTMLElement) {
|
|
76
|
+
const selection = document.getSelection();
|
|
77
|
+
if (!selection || selection.rangeCount === 0) {
|
|
78
|
+
return {start: target.innerText.length, end: target.innerText.length};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const range = selection.getRangeAt(0);
|
|
82
|
+
const start = getIndexedPosition(target, range, true);
|
|
83
|
+
const end = getIndexedPosition(target, range, false);
|
|
84
|
+
return {start, end};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export {getCurrentCursorPosition, moveCursorToEnd, setCursorPosition};
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import * as CursorUtils from './cursorUtils';
|
|
2
|
+
import type * as StyleUtilsTypes from '../styleUtils';
|
|
3
|
+
|
|
4
|
+
type PartialMarkdownStyle = StyleUtilsTypes.PartialMarkdownStyle;
|
|
5
|
+
|
|
6
|
+
type MarkdownType = 'bold' | 'italic' | 'strikethrough' | 'link' | 'code' | 'pre' | 'blockquote' | 'h1' | 'syntax' | 'mention-here' | 'mention-user';
|
|
7
|
+
|
|
8
|
+
type MarkdownRange = {
|
|
9
|
+
type: MarkdownType;
|
|
10
|
+
startIndex: number;
|
|
11
|
+
length: number;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
type NestedNode = {
|
|
15
|
+
node: HTMLElement;
|
|
16
|
+
endIndex: number;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
function addStyling(targetElement: HTMLElement, type: MarkdownType, markdownStyle: PartialMarkdownStyle) {
|
|
20
|
+
const node = targetElement;
|
|
21
|
+
switch (type) {
|
|
22
|
+
case 'syntax':
|
|
23
|
+
Object.assign(node.style, markdownStyle.syntax);
|
|
24
|
+
break;
|
|
25
|
+
case 'bold':
|
|
26
|
+
node.style.fontWeight = 'bold';
|
|
27
|
+
break;
|
|
28
|
+
case 'italic':
|
|
29
|
+
node.style.fontStyle = 'italic';
|
|
30
|
+
break;
|
|
31
|
+
case 'strikethrough':
|
|
32
|
+
node.style.textDecoration = 'line-through';
|
|
33
|
+
break;
|
|
34
|
+
case 'mention-here':
|
|
35
|
+
Object.assign(node.style, markdownStyle.mentionHere);
|
|
36
|
+
break;
|
|
37
|
+
case 'mention-user':
|
|
38
|
+
Object.assign(node.style, markdownStyle.mentionUser);
|
|
39
|
+
break;
|
|
40
|
+
case 'link':
|
|
41
|
+
Object.assign(node.style, {
|
|
42
|
+
...markdownStyle.link,
|
|
43
|
+
textDecoration: 'underline',
|
|
44
|
+
});
|
|
45
|
+
break;
|
|
46
|
+
case 'code':
|
|
47
|
+
Object.assign(node.style, markdownStyle.code);
|
|
48
|
+
break;
|
|
49
|
+
case 'pre':
|
|
50
|
+
Object.assign(node.style, markdownStyle.pre);
|
|
51
|
+
break;
|
|
52
|
+
|
|
53
|
+
case 'blockquote':
|
|
54
|
+
Object.assign(node.style, {
|
|
55
|
+
...markdownStyle.blockquote,
|
|
56
|
+
borderLeftStyle: 'solid',
|
|
57
|
+
display: 'inline-block',
|
|
58
|
+
maxWidth: '100%',
|
|
59
|
+
boxSizing: 'border-box',
|
|
60
|
+
});
|
|
61
|
+
break;
|
|
62
|
+
case 'h1':
|
|
63
|
+
Object.assign(node.style, {
|
|
64
|
+
...markdownStyle.h1,
|
|
65
|
+
fontWeight: 'bold',
|
|
66
|
+
});
|
|
67
|
+
break;
|
|
68
|
+
default:
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function addSubstringAsTextNode(root: HTMLElement, text: string, startIndex: number, endIndex: number) {
|
|
74
|
+
const substring = text.substring(startIndex, endIndex);
|
|
75
|
+
if (substring.length > 0) {
|
|
76
|
+
root.appendChild(document.createTextNode(substring));
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function parseRangesToHTMLNodes(text: string, ranges: MarkdownRange[], markdownStyle: PartialMarkdownStyle = {}, disableInlineStyles = false): HTMLElement {
|
|
81
|
+
const root: HTMLElement = document.createElement('span');
|
|
82
|
+
root.className = 'root';
|
|
83
|
+
const textLength = text.length;
|
|
84
|
+
if (ranges.length === 0) {
|
|
85
|
+
addSubstringAsTextNode(root, text, 0, textLength);
|
|
86
|
+
return root;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const stack = [...ranges];
|
|
90
|
+
const nestedStack: NestedNode[] = [{node: root, endIndex: textLength}];
|
|
91
|
+
let lastRangeEndIndex = 0;
|
|
92
|
+
while (stack.length > 0) {
|
|
93
|
+
const range = stack.shift();
|
|
94
|
+
if (!range) {
|
|
95
|
+
break;
|
|
96
|
+
}
|
|
97
|
+
let currentRoot = nestedStack[nestedStack.length - 1];
|
|
98
|
+
if (!currentRoot) {
|
|
99
|
+
break;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const endOfCurrentRange = range.startIndex + range.length;
|
|
103
|
+
const nextRangeStartIndex = stack.length > 0 && !!stack[0] ? stack[0].startIndex || 0 : textLength;
|
|
104
|
+
|
|
105
|
+
addSubstringAsTextNode(currentRoot.node, text, lastRangeEndIndex, range.startIndex); // add text with newlines before current range
|
|
106
|
+
|
|
107
|
+
const span = document.createElement('span');
|
|
108
|
+
if (disableInlineStyles) {
|
|
109
|
+
span.className = range.type;
|
|
110
|
+
} else {
|
|
111
|
+
addStyling(span, range.type, markdownStyle);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (stack.length > 0 && nextRangeStartIndex < endOfCurrentRange && range.type !== 'syntax') {
|
|
115
|
+
// tag nesting
|
|
116
|
+
currentRoot.node.appendChild(span);
|
|
117
|
+
nestedStack.push({node: span, endIndex: endOfCurrentRange});
|
|
118
|
+
lastRangeEndIndex = range.startIndex;
|
|
119
|
+
} else {
|
|
120
|
+
addSubstringAsTextNode(span, text, range.startIndex, endOfCurrentRange);
|
|
121
|
+
currentRoot.node.appendChild(span);
|
|
122
|
+
lastRangeEndIndex = endOfCurrentRange;
|
|
123
|
+
|
|
124
|
+
// end of tag nesting
|
|
125
|
+
while (nestedStack.length - 1 > 0 && nextRangeStartIndex >= currentRoot.endIndex) {
|
|
126
|
+
addSubstringAsTextNode(currentRoot.node, text, lastRangeEndIndex, currentRoot.endIndex);
|
|
127
|
+
const prevRoot = nestedStack.pop();
|
|
128
|
+
if (!prevRoot) {
|
|
129
|
+
break;
|
|
130
|
+
}
|
|
131
|
+
lastRangeEndIndex = prevRoot.endIndex;
|
|
132
|
+
currentRoot = nestedStack[nestedStack.length - 1] || currentRoot;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (nestedStack.length > 1) {
|
|
138
|
+
const lastNestedNode = nestedStack[nestedStack.length - 1];
|
|
139
|
+
if (lastNestedNode) {
|
|
140
|
+
root.appendChild(lastNestedNode.node);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
addSubstringAsTextNode(root, text, lastRangeEndIndex, textLength);
|
|
145
|
+
return root;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function parseText(
|
|
149
|
+
target: HTMLElement,
|
|
150
|
+
text: string,
|
|
151
|
+
curosrPositionIndex: number | null,
|
|
152
|
+
markdownStyle: PartialMarkdownStyle = {},
|
|
153
|
+
disableNewLinesInCursorPositioning = false,
|
|
154
|
+
alwaysMoveCursorToTheEnd = false,
|
|
155
|
+
) {
|
|
156
|
+
const targetElement = target;
|
|
157
|
+
|
|
158
|
+
let cursorPosition: number | null = curosrPositionIndex;
|
|
159
|
+
const isFocused = document.activeElement === target;
|
|
160
|
+
if (isFocused && curosrPositionIndex === null) {
|
|
161
|
+
cursorPosition = CursorUtils.getCurrentCursorPosition(target).start;
|
|
162
|
+
}
|
|
163
|
+
const ranges = global.parseExpensiMarkToRanges(text);
|
|
164
|
+
|
|
165
|
+
const markdownRanges: MarkdownRange[] = ranges.map((range) => {
|
|
166
|
+
const [type, startIndex, length] = range;
|
|
167
|
+
return {
|
|
168
|
+
type: type as MarkdownType,
|
|
169
|
+
startIndex,
|
|
170
|
+
length,
|
|
171
|
+
};
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
targetElement.innerHTML = '';
|
|
175
|
+
targetElement.innerText = '';
|
|
176
|
+
|
|
177
|
+
// We don't want to parse text with single '\n', because contentEditable represents it as invisible <br />
|
|
178
|
+
if (!!text && text !== '\n') {
|
|
179
|
+
const dom = parseRangesToHTMLNodes(text, markdownRanges, markdownStyle);
|
|
180
|
+
target.appendChild(dom);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (alwaysMoveCursorToTheEnd) {
|
|
184
|
+
CursorUtils.moveCursorToEnd(target);
|
|
185
|
+
} else if (isFocused && cursorPosition !== null) {
|
|
186
|
+
CursorUtils.setCursorPosition(target, cursorPosition, disableNewLinesInCursorPositioning);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
return {text: target.innerText, cursorPosition: cursorPosition || 0};
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
export {parseText, parseRangesToHTMLNodes};
|
|
193
|
+
|
|
194
|
+
export type {MarkdownRange, MarkdownType};
|