@uiw/react-md-editor 3.23.6 → 3.24.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/README.md +29 -4
- package/dist/mdeditor.css +2 -0
- package/dist/mdeditor.js +234 -237
- package/dist/mdeditor.min.css +1 -1
- package/dist/mdeditor.min.js +1 -1
- package/dist/mdeditor.min.js.LICENSE.txt +1 -1
- package/esm/commands/bold.js +9 -13
- package/esm/commands/code.d.ts +1 -1
- package/esm/commands/code.js +75 -68
- package/esm/commands/comment.js +20 -18
- package/esm/commands/help.d.ts +2 -0
- package/esm/commands/help.js +22 -0
- package/esm/commands/hr.js +33 -2
- package/esm/commands/image.js +39 -16
- package/esm/commands/index.d.ts +7 -2
- package/esm/commands/index.js +5 -2
- package/esm/commands/issue.d.ts +2 -0
- package/esm/commands/issue.js +41 -0
- package/esm/commands/italic.js +9 -13
- package/esm/commands/link.js +40 -14
- package/esm/commands/list.d.ts +3 -10
- package/esm/commands/list.js +39 -41
- package/esm/commands/quote.js +8 -8
- package/esm/commands/strikeThrough.js +9 -13
- package/esm/commands/table.d.ts +2 -0
- package/esm/commands/table.js +57 -0
- package/esm/commands/title.d.ts +7 -1
- package/esm/commands/title.js +21 -0
- package/esm/commands/title1.js +9 -7
- package/esm/commands/title2.js +9 -7
- package/esm/commands/title3.js +9 -7
- package/esm/commands/title4.js +9 -7
- package/esm/commands/title5.js +9 -7
- package/esm/commands/title6.js +9 -7
- package/esm/components/TextArea/handleKeyDown.js +83 -5
- package/esm/utils/InsertTextAtPosition.d.ts +0 -7
- package/esm/utils/InsertTextAtPosition.js +6 -24
- package/esm/utils/markdownUtils.d.ts +23 -1
- package/esm/utils/markdownUtils.js +83 -4
- package/lib/Context.js +2 -3
- package/lib/Editor.js +1 -2
- package/lib/commands/bold.js +10 -15
- package/lib/commands/code.d.ts +1 -1
- package/lib/commands/code.js +75 -70
- package/lib/commands/comment.js +21 -20
- package/lib/commands/divider.js +2 -3
- package/lib/commands/fullscreen.js +2 -3
- package/lib/commands/group.js +2 -3
- package/lib/commands/help.d.ts +2 -0
- package/lib/commands/help.js +29 -0
- package/lib/commands/hr.js +35 -5
- package/lib/commands/image.js +40 -18
- package/lib/commands/index.d.ts +7 -2
- package/lib/commands/index.js +27 -10
- package/lib/commands/issue.d.ts +2 -0
- package/lib/commands/issue.js +48 -0
- package/lib/commands/italic.js +10 -15
- package/lib/commands/link.js +41 -16
- package/lib/commands/list.d.ts +3 -10
- package/lib/commands/list.js +43 -52
- package/lib/commands/preview.js +4 -7
- package/lib/commands/quote.js +9 -10
- package/lib/commands/strikeThrough.js +10 -15
- package/lib/commands/table.d.ts +2 -0
- package/lib/commands/table.js +64 -0
- package/lib/commands/title.d.ts +7 -1
- package/lib/commands/title.js +23 -3
- package/lib/commands/title1.js +11 -10
- package/lib/commands/title2.js +11 -10
- package/lib/commands/title3.js +11 -10
- package/lib/commands/title4.js +11 -10
- package/lib/commands/title5.js +11 -10
- package/lib/commands/title6.js +11 -10
- package/lib/components/DragBar/index.js +1 -2
- package/lib/components/TextArea/handleKeyDown.js +84 -6
- package/lib/index.js +1 -2
- package/lib/utils/InsertTextAtPosition.d.ts +0 -7
- package/lib/utils/InsertTextAtPosition.js +6 -26
- package/lib/utils/markdownUtils.d.ts +23 -1
- package/lib/utils/markdownUtils.js +84 -4
- package/package.json +4 -1
- package/src/commands/bold.tsx +13 -12
- package/src/commands/code.tsx +72 -71
- package/src/commands/comment.tsx +20 -15
- package/src/commands/help.tsx +19 -0
- package/src/commands/hr.tsx +33 -2
- package/src/commands/image.tsx +38 -15
- package/src/commands/index.ts +12 -1
- package/src/commands/issue.tsx +36 -0
- package/src/commands/italic.tsx +13 -12
- package/src/commands/link.tsx +39 -12
- package/src/commands/list.tsx +35 -53
- package/src/commands/quote.tsx +14 -13
- package/src/commands/strikeThrough.tsx +13 -12
- package/src/commands/table.tsx +52 -0
- package/src/commands/title.tsx +18 -1
- package/src/commands/title1.tsx +6 -9
- package/src/commands/title2.tsx +6 -9
- package/src/commands/title3.tsx +6 -9
- package/src/commands/title4.tsx +6 -9
- package/src/commands/title5.tsx +6 -9
- package/src/commands/title6.tsx +6 -9
- package/src/components/TextArea/handleKeyDown.tsx +54 -5
- package/src/utils/InsertTextAtPosition.ts +7 -28
- package/src/utils/markdownUtils.ts +94 -4
package/src/commands/title6.tsx
CHANGED
|
@@ -1,19 +1,16 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import {
|
|
3
|
-
import { ICommand,
|
|
2
|
+
import { titleExecute } from '../commands/title';
|
|
3
|
+
import { ICommand, ExecuteState, TextAreaTextApi } from './';
|
|
4
4
|
|
|
5
5
|
export const title6: ICommand = {
|
|
6
6
|
name: 'title6',
|
|
7
7
|
keyCommand: 'title6',
|
|
8
8
|
shortcuts: 'ctrlcmd+6',
|
|
9
|
-
|
|
9
|
+
prefix: '###### ',
|
|
10
|
+
suffix: '',
|
|
10
11
|
buttonProps: { 'aria-label': 'Insert title6 (ctrl + 6)', title: 'Insert title6 (ctrl + 6)' },
|
|
11
12
|
icon: <div style={{ fontSize: 12, textAlign: 'left' }}>Title 6</div>,
|
|
12
|
-
execute: (state:
|
|
13
|
-
|
|
14
|
-
api.replaceSelection('###### ');
|
|
15
|
-
} else {
|
|
16
|
-
insertAtLineStart('###### ', state.selection.start, api.textArea);
|
|
17
|
-
}
|
|
13
|
+
execute: (state: ExecuteState, api: TextAreaTextApi) => {
|
|
14
|
+
titleExecute({ state, api, prefix: state.command.prefix!, suffix: state.command.suffix });
|
|
18
15
|
},
|
|
19
16
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { insertTextAtPosition } from '../../utils/InsertTextAtPosition';
|
|
2
|
+
import { insertBeforeEachLine, selectLine } from '../../utils/markdownUtils';
|
|
2
3
|
import { TextAreaTextApi } from '../../commands';
|
|
3
|
-
import { insertBeforeEachLine } from '../../commands/list';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* - `13` - `Enter`
|
|
@@ -11,6 +11,38 @@ function stopPropagation(e: KeyboardEvent | React.KeyboardEvent<HTMLTextAreaElem
|
|
|
11
11
|
e.preventDefault();
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
+
function handleLineMove(e: KeyboardEvent | React.KeyboardEvent<HTMLTextAreaElement>, direction: number) {
|
|
15
|
+
stopPropagation(e);
|
|
16
|
+
const target = e.target as HTMLTextAreaElement;
|
|
17
|
+
const textArea = new TextAreaTextApi(target);
|
|
18
|
+
let selection = { start: target.selectionStart, end: target.selectionEnd };
|
|
19
|
+
selection = selectLine({ text: target.value, selection });
|
|
20
|
+
if ((direction < 0 && selection.start <= 0) || (direction > 0 && selection.end >= target.value.length)) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const blockText = target.value.slice(selection.start, selection.end);
|
|
25
|
+
if (direction < 0) {
|
|
26
|
+
const prevLineSelection = selectLine({
|
|
27
|
+
text: target.value,
|
|
28
|
+
selection: { start: selection.start - 1, end: selection.start - 1 },
|
|
29
|
+
});
|
|
30
|
+
const prevLineText = target.value.slice(prevLineSelection.start, prevLineSelection.end);
|
|
31
|
+
textArea.setSelectionRange({ start: prevLineSelection.start, end: selection.end });
|
|
32
|
+
insertTextAtPosition(target, `${blockText}\n${prevLineText}`);
|
|
33
|
+
textArea.setSelectionRange({ start: prevLineSelection.start, end: prevLineSelection.start + blockText.length });
|
|
34
|
+
} else {
|
|
35
|
+
const nextLineSelection = selectLine({
|
|
36
|
+
text: target.value,
|
|
37
|
+
selection: { start: selection.end + 1, end: selection.end + 1 },
|
|
38
|
+
});
|
|
39
|
+
const nextLineText = target.value.slice(nextLineSelection.start, nextLineSelection.end);
|
|
40
|
+
textArea.setSelectionRange({ start: selection.start, end: nextLineSelection.end });
|
|
41
|
+
insertTextAtPosition(target, `${nextLineText}\n${blockText}`);
|
|
42
|
+
textArea.setSelectionRange({ start: nextLineSelection.end - blockText.length, end: nextLineSelection.end });
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
14
46
|
export default function handleKeyDown(
|
|
15
47
|
e: KeyboardEvent | React.KeyboardEvent<HTMLTextAreaElement>,
|
|
16
48
|
tabSize: number = 2,
|
|
@@ -70,7 +102,8 @@ export default function handleKeyDown(
|
|
|
70
102
|
} else if (
|
|
71
103
|
e.keyCode === 13 &&
|
|
72
104
|
e.code.toLowerCase() === 'enter' &&
|
|
73
|
-
(/^(-|\*)\s/.test(currentLineStr) || /^\d+.\s/.test(currentLineStr))
|
|
105
|
+
(/^(-|\*)\s/.test(currentLineStr) || /^\d+.\s/.test(currentLineStr)) &&
|
|
106
|
+
!e.shiftKey
|
|
74
107
|
) {
|
|
75
108
|
/**
|
|
76
109
|
* `13` - `Enter`
|
|
@@ -82,15 +115,31 @@ export default function handleKeyDown(
|
|
|
82
115
|
startStr = '\n* ';
|
|
83
116
|
}
|
|
84
117
|
|
|
85
|
-
if (
|
|
118
|
+
if (
|
|
119
|
+
currentLineStr.startsWith('- [ ]') ||
|
|
120
|
+
currentLineStr.startsWith('- [X]') ||
|
|
121
|
+
currentLineStr.startsWith('- [x]')
|
|
122
|
+
) {
|
|
86
123
|
startStr = '\n- [ ] ';
|
|
87
|
-
} else if (currentLineStr.startsWith('- [X]')) {
|
|
88
|
-
startStr = '\n- [X] ';
|
|
89
124
|
}
|
|
90
125
|
|
|
91
126
|
if (/^\d+.\s/.test(currentLineStr)) {
|
|
92
127
|
startStr = `\n${parseInt(currentLineStr) + 1}. `;
|
|
93
128
|
}
|
|
94
129
|
return insertTextAtPosition(target, startStr);
|
|
130
|
+
} else if (e.code && e.code.toLowerCase() === 'keyd' && e.ctrlKey) {
|
|
131
|
+
// Duplicate lines
|
|
132
|
+
stopPropagation(e);
|
|
133
|
+
let selection = { start: target.selectionStart, end: target.selectionEnd };
|
|
134
|
+
const savedSelection = selection;
|
|
135
|
+
selection = selectLine({ text: target.value, selection });
|
|
136
|
+
const textToDuplicate = target.value.slice(selection.start, selection.end);
|
|
137
|
+
textArea.setSelectionRange({ start: selection.end, end: selection.end });
|
|
138
|
+
insertTextAtPosition(target, `\n${textToDuplicate}`);
|
|
139
|
+
textArea.setSelectionRange({ start: savedSelection.start, end: savedSelection.end });
|
|
140
|
+
} else if (e.code && e.code.toLowerCase() === 'arrowup' && e.altKey) {
|
|
141
|
+
handleLineMove(e, -1);
|
|
142
|
+
} else if (e.code && e.code.toLowerCase() === 'arrowdown' && e.altKey) {
|
|
143
|
+
handleLineMove(e, 1);
|
|
95
144
|
}
|
|
96
145
|
}
|
|
@@ -22,33 +22,6 @@ function canManipulateViaTextNodes(input: HTMLTextAreaElement | HTMLInputElement
|
|
|
22
22
|
return browserSupportsTextareaTextNodes;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
/**
|
|
26
|
-
* @param {string} val
|
|
27
|
-
* @param {number} cursorIdx
|
|
28
|
-
* @param {HTMLTextAreaElement|HTMLInputElement} input
|
|
29
|
-
* @return {void}
|
|
30
|
-
*/
|
|
31
|
-
export const insertAtLineStart = (
|
|
32
|
-
val: string,
|
|
33
|
-
cursorIdx: number,
|
|
34
|
-
input: HTMLTextAreaElement | HTMLInputElement,
|
|
35
|
-
): void => {
|
|
36
|
-
const content = input.value;
|
|
37
|
-
let startIdx = 0;
|
|
38
|
-
|
|
39
|
-
while (cursorIdx--) {
|
|
40
|
-
let char = content[cursorIdx];
|
|
41
|
-
if (char === '\n') {
|
|
42
|
-
startIdx = cursorIdx + 1;
|
|
43
|
-
break;
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
input.focus();
|
|
48
|
-
input.setRangeText(val, startIdx, startIdx);
|
|
49
|
-
input.dispatchEvent(new Event('input', { bubbles: true }));
|
|
50
|
-
};
|
|
51
|
-
|
|
52
25
|
/**
|
|
53
26
|
* @param {HTMLTextAreaElement|HTMLInputElement} input
|
|
54
27
|
* @param {string} text
|
|
@@ -71,7 +44,13 @@ export function insertTextAtPosition(input: HTMLTextAreaElement | HTMLInputEleme
|
|
|
71
44
|
}
|
|
72
45
|
|
|
73
46
|
// Webkit + Edge
|
|
74
|
-
|
|
47
|
+
let isSuccess = false;
|
|
48
|
+
if (text !== '') {
|
|
49
|
+
isSuccess = document.execCommand && document.execCommand('insertText', false, text);
|
|
50
|
+
} else {
|
|
51
|
+
isSuccess = document.execCommand && document.execCommand('delete', false);
|
|
52
|
+
}
|
|
53
|
+
|
|
75
54
|
if (!isSuccess) {
|
|
76
55
|
const start = input.selectionStart!;
|
|
77
56
|
const end = input.selectionEnd!;
|
|
@@ -1,16 +1,42 @@
|
|
|
1
1
|
import { TextRange } from '../commands';
|
|
2
|
+
import { TextAreaTextApi, ExecuteState } from '../commands';
|
|
2
3
|
|
|
3
4
|
export interface TextSection {
|
|
4
5
|
text: string;
|
|
5
6
|
selection: TextRange;
|
|
6
7
|
}
|
|
7
8
|
|
|
8
|
-
export function selectWord({
|
|
9
|
+
export function selectWord({
|
|
10
|
+
text,
|
|
11
|
+
selection,
|
|
12
|
+
prefix,
|
|
13
|
+
suffix = prefix,
|
|
14
|
+
}: {
|
|
15
|
+
text: string;
|
|
16
|
+
selection: TextRange;
|
|
17
|
+
prefix: string;
|
|
18
|
+
suffix?: string;
|
|
19
|
+
}): TextRange {
|
|
20
|
+
let result = selection;
|
|
9
21
|
if (text && text.length && selection.start === selection.end) {
|
|
10
|
-
|
|
11
|
-
|
|
22
|
+
result = getSurroundingWord(text, selection.start);
|
|
23
|
+
}
|
|
24
|
+
if (result.start >= prefix.length && result.end <= text.length - suffix.length) {
|
|
25
|
+
const selectedTextContext = text.slice(result.start - prefix.length, result.end + suffix.length);
|
|
26
|
+
if (selectedTextContext.startsWith(prefix) && selectedTextContext.endsWith(suffix)) {
|
|
27
|
+
return { start: result.start - prefix.length, end: result.end + suffix.length };
|
|
28
|
+
}
|
|
12
29
|
}
|
|
13
|
-
return
|
|
30
|
+
return result;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function selectLine({ text, selection }: TextSection): TextRange {
|
|
34
|
+
const start = text.slice(0, selection.start).lastIndexOf('\n') + 1;
|
|
35
|
+
let end = text.slice(selection.end).indexOf('\n') + selection.end;
|
|
36
|
+
if (end === selection.end - 1) {
|
|
37
|
+
end = text.length;
|
|
38
|
+
}
|
|
39
|
+
return { start, end };
|
|
14
40
|
}
|
|
15
41
|
|
|
16
42
|
/**
|
|
@@ -100,3 +126,67 @@ export function getSurroundingWord(text: string, position: number): TextRange {
|
|
|
100
126
|
|
|
101
127
|
return { start, end };
|
|
102
128
|
}
|
|
129
|
+
|
|
130
|
+
export function executeCommand({
|
|
131
|
+
api,
|
|
132
|
+
selectedText,
|
|
133
|
+
selection,
|
|
134
|
+
prefix,
|
|
135
|
+
suffix = prefix,
|
|
136
|
+
}: {
|
|
137
|
+
api: TextAreaTextApi;
|
|
138
|
+
selectedText: string;
|
|
139
|
+
selection: TextRange;
|
|
140
|
+
prefix: string;
|
|
141
|
+
suffix?: string;
|
|
142
|
+
}) {
|
|
143
|
+
if (
|
|
144
|
+
selectedText.length >= prefix.length + suffix.length &&
|
|
145
|
+
selectedText.startsWith(prefix) &&
|
|
146
|
+
selectedText.endsWith(suffix)
|
|
147
|
+
) {
|
|
148
|
+
api.replaceSelection(selectedText.slice(prefix.length, suffix.length ? -suffix.length : undefined));
|
|
149
|
+
api.setSelectionRange({ start: selection.start - prefix.length, end: selection.end - prefix.length });
|
|
150
|
+
} else {
|
|
151
|
+
api.replaceSelection(`${prefix}${selectedText}${suffix}`);
|
|
152
|
+
api.setSelectionRange({ start: selection.start + prefix.length, end: selection.end + prefix.length });
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export type AlterLineFunction = (line: string, index: number) => string;
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Inserts insertionString before each line
|
|
160
|
+
*/
|
|
161
|
+
export function insertBeforeEachLine(
|
|
162
|
+
selectedText: string,
|
|
163
|
+
insertBefore: string | AlterLineFunction,
|
|
164
|
+
): { modifiedText: string; insertionLength: number } {
|
|
165
|
+
const lines = selectedText.split(/\n/);
|
|
166
|
+
|
|
167
|
+
let insertionLength = 0;
|
|
168
|
+
const modifiedText = lines
|
|
169
|
+
.map((item, index) => {
|
|
170
|
+
if (typeof insertBefore === 'string') {
|
|
171
|
+
if (item.startsWith(insertBefore)) {
|
|
172
|
+
insertionLength -= insertBefore.length;
|
|
173
|
+
return item.slice(insertBefore.length);
|
|
174
|
+
}
|
|
175
|
+
insertionLength += insertBefore.length;
|
|
176
|
+
return insertBefore + item;
|
|
177
|
+
}
|
|
178
|
+
if (typeof insertBefore === 'function') {
|
|
179
|
+
if (item.startsWith(insertBefore(item, index))) {
|
|
180
|
+
insertionLength -= insertBefore(item, index).length;
|
|
181
|
+
return item.slice(insertBefore(item, index).length);
|
|
182
|
+
}
|
|
183
|
+
const insertionResult = insertBefore(item, index);
|
|
184
|
+
insertionLength += insertionResult.length;
|
|
185
|
+
return insertBefore(item, index) + item;
|
|
186
|
+
}
|
|
187
|
+
throw Error('insertion is expected to be either a string or a function');
|
|
188
|
+
})
|
|
189
|
+
.join('\n');
|
|
190
|
+
|
|
191
|
+
return { modifiedText, insertionLength };
|
|
192
|
+
}
|