@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/index.ts
CHANGED
|
@@ -22,6 +22,9 @@ import { title3 } from './title3';
|
|
|
22
22
|
import { title4 } from './title4';
|
|
23
23
|
import { title5 } from './title5';
|
|
24
24
|
import { title6 } from './title6';
|
|
25
|
+
import { table } from './table';
|
|
26
|
+
import { issue } from './issue';
|
|
27
|
+
import { help } from './help';
|
|
25
28
|
|
|
26
29
|
export interface CommandOrchestrator {
|
|
27
30
|
executeCommand(command: ICommand): void;
|
|
@@ -48,7 +51,9 @@ export interface ICommandBase<T> {
|
|
|
48
51
|
shortcuts?: string;
|
|
49
52
|
groupName?: string;
|
|
50
53
|
icon?: React.ReactElement;
|
|
51
|
-
value?:
|
|
54
|
+
value?: string;
|
|
55
|
+
prefix?: string;
|
|
56
|
+
suffix?: string;
|
|
52
57
|
position?: 'right';
|
|
53
58
|
liProps?: React.LiHTMLAttributes<HTMLLIElement>;
|
|
54
59
|
buttonProps?: React.ButtonHTMLAttributes<HTMLButtonElement> | null;
|
|
@@ -99,10 +104,13 @@ const getCommands: () => ICommand[] = () => [
|
|
|
99
104
|
codeBlock,
|
|
100
105
|
comment,
|
|
101
106
|
image,
|
|
107
|
+
table,
|
|
102
108
|
divider,
|
|
103
109
|
unorderedListCommand,
|
|
104
110
|
orderedListCommand,
|
|
105
111
|
checkedListCommand,
|
|
112
|
+
divider,
|
|
113
|
+
help,
|
|
106
114
|
];
|
|
107
115
|
|
|
108
116
|
const getExtraCommands: () => ICommand[] = () => [codeEdit, codeLive, codePreview, divider, fullscreen];
|
|
@@ -195,6 +203,9 @@ export {
|
|
|
195
203
|
unorderedListCommand,
|
|
196
204
|
orderedListCommand,
|
|
197
205
|
checkedListCommand,
|
|
206
|
+
table,
|
|
207
|
+
issue,
|
|
208
|
+
help,
|
|
198
209
|
codeEdit,
|
|
199
210
|
codeLive,
|
|
200
211
|
codePreview,
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { ICommand, ExecuteState, TextAreaTextApi } from './';
|
|
3
|
+
import { selectWord, executeCommand } from '../utils/markdownUtils';
|
|
4
|
+
|
|
5
|
+
export const issue: ICommand = {
|
|
6
|
+
name: 'issue',
|
|
7
|
+
keyCommand: 'issue',
|
|
8
|
+
prefix: '#',
|
|
9
|
+
suffix: '',
|
|
10
|
+
buttonProps: { 'aria-label': 'Add issue', title: 'Add issue' },
|
|
11
|
+
icon: (
|
|
12
|
+
<svg role="img" width="12" height="12" viewBox="0 0 448 512">
|
|
13
|
+
<path
|
|
14
|
+
fill="currentColor"
|
|
15
|
+
d="M181.3 32.4c17.4 2.9 29.2 19.4 26.3 36.8L197.8 128h95.1l11.5-69.3c2.9-17.4 19.4-29.2 36.8-26.3s29.2 19.4 26.3 36.8L357.8 128H416c17.7 0 32 14.3 32 32s-14.3 32-32 32H347.1L325.8 320H384c17.7 0 32 14.3 32 32s-14.3 32-32 32H315.1l-11.5 69.3c-2.9 17.4-19.4 29.2-36.826.3s-29.2-19.4-26.3-36.8l9.8-58.7H155.1l-11.5 69.3c-2.9 17.4-19.4 29.2-36.8 26.3s-29.2-19.4-26.3-36.8L90.2 384H32c-17.7 0-32-14.3-32-32s14.3-32 32-32h68.9l21.3-128H64c-17.7 0-32-14.3-32-32s14.3-32 32-32h68.9l11.5-69.3c2.9-17.4 19.4-29.2 36.8-26.3zM187.1 192L165.8320h95.1l21.3-128H187.1z"
|
|
16
|
+
//Font Awesome Free 6.4.2 by @fontawesome - https://fontawesome.com
|
|
17
|
+
/>
|
|
18
|
+
</svg>
|
|
19
|
+
),
|
|
20
|
+
execute: (state: ExecuteState, api: TextAreaTextApi) => {
|
|
21
|
+
const newSelectionRange = selectWord({
|
|
22
|
+
text: state.text,
|
|
23
|
+
selection: state.selection,
|
|
24
|
+
prefix: state.command.prefix!,
|
|
25
|
+
suffix: state.command.suffix,
|
|
26
|
+
});
|
|
27
|
+
const state1 = api.setSelectionRange(newSelectionRange);
|
|
28
|
+
executeCommand({
|
|
29
|
+
api,
|
|
30
|
+
selectedText: state1.selectedText,
|
|
31
|
+
selection: state.selection,
|
|
32
|
+
prefix: state.command.prefix!,
|
|
33
|
+
suffix: state.command.suffix,
|
|
34
|
+
});
|
|
35
|
+
},
|
|
36
|
+
};
|
package/src/commands/italic.tsx
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { ICommand, ExecuteState, TextAreaTextApi } from './';
|
|
3
|
-
import { selectWord } from '../utils/markdownUtils';
|
|
3
|
+
import { selectWord, executeCommand } from '../utils/markdownUtils';
|
|
4
4
|
|
|
5
5
|
export const italic: ICommand = {
|
|
6
6
|
name: 'italic',
|
|
7
7
|
keyCommand: 'italic',
|
|
8
8
|
shortcuts: 'ctrlcmd+i',
|
|
9
|
-
|
|
9
|
+
prefix: '*',
|
|
10
10
|
buttonProps: { 'aria-label': 'Add italic text (ctrl + i)', title: 'Add italic text (ctrl + i)' },
|
|
11
11
|
icon: (
|
|
12
12
|
<svg data-name="italic" width="12" height="12" role="img" viewBox="0 0 320 512">
|
|
@@ -17,16 +17,17 @@ export const italic: ICommand = {
|
|
|
17
17
|
</svg>
|
|
18
18
|
),
|
|
19
19
|
execute: (state: ExecuteState, api: TextAreaTextApi) => {
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
const newSelectionRange = selectWord({
|
|
21
|
+
text: state.text,
|
|
22
|
+
selection: state.selection,
|
|
23
|
+
prefix: state.command.prefix!,
|
|
24
|
+
});
|
|
22
25
|
const state1 = api.setSelectionRange(newSelectionRange);
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
// Adjust the selection to not contain the **
|
|
30
|
-
api.setSelectionRange({ start, end });
|
|
26
|
+
executeCommand({
|
|
27
|
+
api,
|
|
28
|
+
selectedText: state1.selectedText,
|
|
29
|
+
selection: state.selection,
|
|
30
|
+
prefix: state.command.prefix!,
|
|
31
|
+
});
|
|
31
32
|
},
|
|
32
33
|
};
|
package/src/commands/link.tsx
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { ICommand, ExecuteState, TextAreaTextApi } from './';
|
|
3
|
-
import { selectWord } from '../utils/markdownUtils';
|
|
3
|
+
import { selectWord, executeCommand } from '../utils/markdownUtils';
|
|
4
4
|
|
|
5
5
|
export const link: ICommand = {
|
|
6
6
|
name: 'link',
|
|
7
7
|
keyCommand: 'link',
|
|
8
8
|
shortcuts: 'ctrlcmd+l',
|
|
9
|
-
|
|
9
|
+
prefix: '[',
|
|
10
|
+
suffix: '](url)',
|
|
10
11
|
buttonProps: { 'aria-label': 'Add a link (ctrl + l)', title: 'Add a link (ctrl + l)' },
|
|
11
12
|
icon: (
|
|
12
13
|
<svg data-name="italic" width="12" height="12" role="img" viewBox="0 0 520 520">
|
|
@@ -17,15 +18,41 @@ export const link: ICommand = {
|
|
|
17
18
|
</svg>
|
|
18
19
|
),
|
|
19
20
|
execute: (state: ExecuteState, api: TextAreaTextApi) => {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
21
|
+
let newSelectionRange = selectWord({
|
|
22
|
+
text: state.text,
|
|
23
|
+
selection: state.selection,
|
|
24
|
+
prefix: state.command.prefix!,
|
|
25
|
+
suffix: state.command.suffix,
|
|
26
|
+
});
|
|
27
|
+
let state1 = api.setSelectionRange(newSelectionRange);
|
|
28
|
+
if (state1.selectedText.includes('http') || state1.selectedText.includes('www')) {
|
|
29
|
+
newSelectionRange = selectWord({ text: state.text, selection: state.selection, prefix: '[](', suffix: ')' });
|
|
30
|
+
state1 = api.setSelectionRange(newSelectionRange);
|
|
31
|
+
executeCommand({
|
|
32
|
+
api,
|
|
33
|
+
selectedText: state1.selectedText,
|
|
34
|
+
selection: state.selection,
|
|
35
|
+
prefix: '[](',
|
|
36
|
+
suffix: ')',
|
|
37
|
+
});
|
|
38
|
+
} else {
|
|
39
|
+
if (state1.selectedText.length === 0) {
|
|
40
|
+
executeCommand({
|
|
41
|
+
api,
|
|
42
|
+
selectedText: state1.selectedText,
|
|
43
|
+
selection: state.selection,
|
|
44
|
+
prefix: '[title',
|
|
45
|
+
suffix: '](url)',
|
|
46
|
+
});
|
|
47
|
+
} else {
|
|
48
|
+
executeCommand({
|
|
49
|
+
api,
|
|
50
|
+
selectedText: state1.selectedText,
|
|
51
|
+
selection: state.selection,
|
|
52
|
+
prefix: state.command.prefix!,
|
|
53
|
+
suffix: state.command.suffix,
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
}
|
|
30
57
|
},
|
|
31
58
|
};
|
package/src/commands/list.tsx
CHANGED
|
@@ -1,43 +1,15 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { ICommand,
|
|
2
|
+
import { ICommand, ExecuteState, TextAreaTextApi } from './';
|
|
3
3
|
import {
|
|
4
4
|
selectWord,
|
|
5
5
|
getBreaksNeededForEmptyLineBefore,
|
|
6
6
|
getBreaksNeededForEmptyLineAfter,
|
|
7
|
+
insertBeforeEachLine,
|
|
8
|
+
AlterLineFunction,
|
|
7
9
|
} from '../utils/markdownUtils';
|
|
8
10
|
|
|
9
|
-
export
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Inserts insertionString before each line
|
|
13
|
-
*/
|
|
14
|
-
export function insertBeforeEachLine(
|
|
15
|
-
selectedText: string,
|
|
16
|
-
insertBefore: string | AlterLineFunction,
|
|
17
|
-
): { modifiedText: string; insertionLength: number } {
|
|
18
|
-
const lines = selectedText.split(/\n/);
|
|
19
|
-
|
|
20
|
-
let insertionLength = 0;
|
|
21
|
-
const modifiedText = lines
|
|
22
|
-
.map((item, index) => {
|
|
23
|
-
if (typeof insertBefore === 'string') {
|
|
24
|
-
insertionLength += insertBefore.length;
|
|
25
|
-
return insertBefore + item;
|
|
26
|
-
} else if (typeof insertBefore === 'function') {
|
|
27
|
-
const insertionResult = insertBefore(item, index);
|
|
28
|
-
insertionLength += insertionResult.length;
|
|
29
|
-
return insertBefore(item, index) + item;
|
|
30
|
-
}
|
|
31
|
-
throw Error('insertion is expected to be either a string or a function');
|
|
32
|
-
})
|
|
33
|
-
.join('\n');
|
|
34
|
-
|
|
35
|
-
return { modifiedText, insertionLength };
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export const makeList = (state: TextState, api: TextAreaTextApi, insertBefore: string | AlterLineFunction) => {
|
|
39
|
-
// Adjust the selection to encompass the whole word if the caret is inside one
|
|
40
|
-
const newSelectionRange = selectWord({ text: state.text, selection: state.selection });
|
|
11
|
+
export const makeList = (state: ExecuteState, api: TextAreaTextApi, insertBefore: string | AlterLineFunction) => {
|
|
12
|
+
const newSelectionRange = selectWord({ text: state.text, selection: state.selection, prefix: state.command.prefix! });
|
|
41
13
|
const state1 = api.setSelectionRange(newSelectionRange);
|
|
42
14
|
|
|
43
15
|
const breaksBeforeCount = getBreaksNeededForEmptyLineBefore(state1.text, state1.selection.start);
|
|
@@ -46,28 +18,38 @@ export const makeList = (state: TextState, api: TextAreaTextApi, insertBefore: s
|
|
|
46
18
|
const breaksAfterCount = getBreaksNeededForEmptyLineAfter(state1.text, state1.selection.end);
|
|
47
19
|
const breaksAfter = Array(breaksAfterCount + 1).join('\n');
|
|
48
20
|
|
|
49
|
-
const modifiedText = insertBeforeEachLine(state1.selectedText, insertBefore);
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
21
|
+
const { modifiedText, insertionLength } = insertBeforeEachLine(state1.selectedText, insertBefore);
|
|
22
|
+
if (insertionLength < 0) {
|
|
23
|
+
// Remove
|
|
24
|
+
let selectionStart = state1.selection.start;
|
|
25
|
+
let selectionEnd = state1.selection.end;
|
|
26
|
+
if (state1.selection.start > 0 && state.text.slice(state1.selection.start - 1, state1.selection.start) === '\n') {
|
|
27
|
+
selectionStart -= 1;
|
|
28
|
+
}
|
|
29
|
+
if (
|
|
30
|
+
state1.selection.end < state.text.length - 1 &&
|
|
31
|
+
state.text.slice(state1.selection.end, state1.selection.end + 1) === '\n'
|
|
32
|
+
) {
|
|
33
|
+
selectionEnd += 1;
|
|
34
|
+
}
|
|
58
35
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
start: selectionStart,
|
|
62
|
-
|
|
63
|
-
|
|
36
|
+
api.setSelectionRange({ start: selectionStart, end: selectionEnd });
|
|
37
|
+
api.replaceSelection(`${modifiedText}`);
|
|
38
|
+
api.setSelectionRange({ start: selectionStart, end: selectionStart + modifiedText.length });
|
|
39
|
+
} else {
|
|
40
|
+
// Add
|
|
41
|
+
api.replaceSelection(`${breaksBefore}${modifiedText}${breaksAfter}`);
|
|
42
|
+
const selectionStart = state1.selection.start + breaksBeforeCount;
|
|
43
|
+
const selectionEnd = selectionStart + modifiedText.length;
|
|
44
|
+
api.setSelectionRange({ start: selectionStart, end: selectionEnd });
|
|
45
|
+
}
|
|
64
46
|
};
|
|
65
47
|
|
|
66
48
|
export const unorderedListCommand: ICommand = {
|
|
67
49
|
name: 'unordered-list',
|
|
68
50
|
keyCommand: 'list',
|
|
69
51
|
shortcuts: 'ctrl+shift+u',
|
|
70
|
-
|
|
52
|
+
prefix: '- ',
|
|
71
53
|
buttonProps: {
|
|
72
54
|
'aria-label': 'Add unordered list (ctrl + shift + u)',
|
|
73
55
|
title: 'Add unordered list (ctrl + shift + u)',
|
|
@@ -80,7 +62,7 @@ export const unorderedListCommand: ICommand = {
|
|
|
80
62
|
/>
|
|
81
63
|
</svg>
|
|
82
64
|
),
|
|
83
|
-
execute: (state:
|
|
65
|
+
execute: (state: ExecuteState, api: TextAreaTextApi) => {
|
|
84
66
|
makeList(state, api, '- ');
|
|
85
67
|
},
|
|
86
68
|
};
|
|
@@ -89,7 +71,7 @@ export const orderedListCommand: ICommand = {
|
|
|
89
71
|
name: 'ordered-list',
|
|
90
72
|
keyCommand: 'list',
|
|
91
73
|
shortcuts: 'ctrl+shift+o',
|
|
92
|
-
|
|
74
|
+
prefix: '1. ',
|
|
93
75
|
buttonProps: { 'aria-label': 'Add ordered list (ctrl + shift + o)', title: 'Add ordered list (ctrl + shift + o)' },
|
|
94
76
|
icon: (
|
|
95
77
|
<svg data-name="ordered-list" width="12" height="12" role="img" viewBox="0 0 512 512">
|
|
@@ -99,7 +81,7 @@ export const orderedListCommand: ICommand = {
|
|
|
99
81
|
/>
|
|
100
82
|
</svg>
|
|
101
83
|
),
|
|
102
|
-
execute: (state:
|
|
84
|
+
execute: (state: ExecuteState, api: TextAreaTextApi) => {
|
|
103
85
|
makeList(state, api, (item, index) => `${index + 1}. `);
|
|
104
86
|
},
|
|
105
87
|
};
|
|
@@ -108,7 +90,7 @@ export const checkedListCommand: ICommand = {
|
|
|
108
90
|
name: 'checked-list',
|
|
109
91
|
keyCommand: 'list',
|
|
110
92
|
shortcuts: 'ctrl+shift+c',
|
|
111
|
-
|
|
93
|
+
prefix: '- [ ] ',
|
|
112
94
|
buttonProps: { 'aria-label': 'Add checked list (ctrl + shift + c)', title: 'Add checked list (ctrl + shift + c)' },
|
|
113
95
|
icon: (
|
|
114
96
|
<svg data-name="checked-list" width="12" height="12" role="img" viewBox="0 0 512 512">
|
|
@@ -118,7 +100,7 @@ export const checkedListCommand: ICommand = {
|
|
|
118
100
|
/>
|
|
119
101
|
</svg>
|
|
120
102
|
),
|
|
121
|
-
execute: (state:
|
|
103
|
+
execute: (state: ExecuteState, api: TextAreaTextApi) => {
|
|
122
104
|
makeList(state, api, (item, index) => `- [ ] `);
|
|
123
105
|
},
|
|
124
106
|
};
|
package/src/commands/quote.tsx
CHANGED
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { ICommand,
|
|
2
|
+
import { ICommand, ExecuteState, TextAreaTextApi } from './';
|
|
3
3
|
import {
|
|
4
4
|
getBreaksNeededForEmptyLineBefore,
|
|
5
5
|
getBreaksNeededForEmptyLineAfter,
|
|
6
6
|
selectWord,
|
|
7
|
+
insertBeforeEachLine,
|
|
7
8
|
} from '../utils/markdownUtils';
|
|
8
9
|
|
|
9
10
|
export const quote: ICommand = {
|
|
10
11
|
name: 'quote',
|
|
11
12
|
keyCommand: 'quote',
|
|
12
13
|
shortcuts: 'ctrlcmd+q',
|
|
14
|
+
prefix: '> ',
|
|
13
15
|
buttonProps: { 'aria-label': 'Insert a quote (ctrl + q)', title: 'Insert a quote (ctrl + q)' },
|
|
14
16
|
icon: (
|
|
15
17
|
<svg width="12" height="12" viewBox="0 0 520 520">
|
|
@@ -19,9 +21,12 @@ export const quote: ICommand = {
|
|
|
19
21
|
/>
|
|
20
22
|
</svg>
|
|
21
23
|
),
|
|
22
|
-
execute: (state:
|
|
23
|
-
|
|
24
|
-
|
|
24
|
+
execute: (state: ExecuteState, api: TextAreaTextApi) => {
|
|
25
|
+
const newSelectionRange = selectWord({
|
|
26
|
+
text: state.text,
|
|
27
|
+
selection: state.selection,
|
|
28
|
+
prefix: state.command.prefix!,
|
|
29
|
+
});
|
|
25
30
|
const state1 = api.setSelectionRange(newSelectionRange);
|
|
26
31
|
const breaksBeforeCount = getBreaksNeededForEmptyLineBefore(state1.text, state1.selection.start);
|
|
27
32
|
const breaksBefore = Array(breaksBeforeCount + 1).join('\n');
|
|
@@ -29,15 +34,11 @@ export const quote: ICommand = {
|
|
|
29
34
|
const breaksAfterCount = getBreaksNeededForEmptyLineAfter(state1.text, state1.selection.end);
|
|
30
35
|
const breaksAfter = Array(breaksAfterCount + 1).join('\n');
|
|
31
36
|
|
|
32
|
-
|
|
33
|
-
api.replaceSelection(`${breaksBefore}
|
|
34
|
-
|
|
35
|
-
const selectionStart = state1.selection.start + breaksBeforeCount + 2;
|
|
36
|
-
const selectionEnd = selectionStart + state1.selectedText.length;
|
|
37
|
+
const modifiedText = insertBeforeEachLine(state1.selectedText, state.command.prefix!);
|
|
38
|
+
api.replaceSelection(`${breaksBefore}${modifiedText.modifiedText}${breaksAfter}`);
|
|
37
39
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
});
|
|
40
|
+
const selectionStart = state1.selection.start + breaksBeforeCount;
|
|
41
|
+
const selectionEnd = selectionStart + modifiedText.modifiedText.length;
|
|
42
|
+
api.setSelectionRange({ start: selectionStart, end: selectionEnd });
|
|
42
43
|
},
|
|
43
44
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { ICommand, ExecuteState, TextAreaTextApi } from './';
|
|
3
|
-
import { selectWord } from '../utils/markdownUtils';
|
|
3
|
+
import { selectWord, executeCommand } from '../utils/markdownUtils';
|
|
4
4
|
|
|
5
5
|
export const strikethrough: ICommand = {
|
|
6
6
|
name: 'strikethrough',
|
|
@@ -10,7 +10,7 @@ export const strikethrough: ICommand = {
|
|
|
10
10
|
'aria-label': 'Add strikethrough text (ctrl + shift + x)',
|
|
11
11
|
title: 'Add strikethrough text (ctrl + shift + x)',
|
|
12
12
|
},
|
|
13
|
-
|
|
13
|
+
prefix: '~~',
|
|
14
14
|
icon: (
|
|
15
15
|
<svg data-name="strikethrough" width="12" height="12" role="img" viewBox="0 0 512 512">
|
|
16
16
|
<path
|
|
@@ -20,16 +20,17 @@ export const strikethrough: ICommand = {
|
|
|
20
20
|
</svg>
|
|
21
21
|
),
|
|
22
22
|
execute: (state: ExecuteState, api: TextAreaTextApi) => {
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
const newSelectionRange = selectWord({
|
|
24
|
+
text: state.text,
|
|
25
|
+
selection: state.selection,
|
|
26
|
+
prefix: state.command.prefix!,
|
|
27
|
+
});
|
|
25
28
|
const state1 = api.setSelectionRange(newSelectionRange);
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
// Adjust the selection to not contain the **
|
|
33
|
-
api.setSelectionRange({ start, end });
|
|
29
|
+
executeCommand({
|
|
30
|
+
api,
|
|
31
|
+
selectedText: state1.selectedText,
|
|
32
|
+
selection: state.selection,
|
|
33
|
+
prefix: state.command.prefix!,
|
|
34
|
+
});
|
|
34
35
|
},
|
|
35
36
|
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { ICommand, ExecuteState, TextAreaTextApi } from './';
|
|
3
|
+
import { selectWord, executeCommand } from '../utils/markdownUtils';
|
|
4
|
+
|
|
5
|
+
export const table: ICommand = {
|
|
6
|
+
name: 'table',
|
|
7
|
+
keyCommand: 'table',
|
|
8
|
+
prefix: '\n| Header | Header |\n|--------|--------|\n| Cell | Cell |\n| Cell | Cell |\n| Cell | Cell |\n\n',
|
|
9
|
+
suffix: '',
|
|
10
|
+
buttonProps: { 'aria-label': 'Add table', title: 'Add table' },
|
|
11
|
+
icon: (
|
|
12
|
+
<svg role="img" width="12" height="12" viewBox="0 0 512 512">
|
|
13
|
+
<path
|
|
14
|
+
fill="currentColor"
|
|
15
|
+
d="M64 256V160H224v96H64zm0 64H224v96H64V320zm224 96V320H448v96H288zM448 256H288V160H448v96zM64 32C28.7 32 0 60.7 0 96V416c0 35.3 28.7 64 64 64H448c35.3 0 64-28.7 64-64V96c0-35.3-28.7-64-64-64H64z"
|
|
16
|
+
//Font Awesome Free 6.4.2 by @fontawesome - https://fontawesome.com
|
|
17
|
+
/>
|
|
18
|
+
</svg>
|
|
19
|
+
),
|
|
20
|
+
execute: (state: ExecuteState, api: TextAreaTextApi) => {
|
|
21
|
+
const newSelectionRange = selectWord({
|
|
22
|
+
text: state.text,
|
|
23
|
+
selection: state.selection,
|
|
24
|
+
prefix: state.command.prefix!,
|
|
25
|
+
suffix: state.command.suffix,
|
|
26
|
+
});
|
|
27
|
+
let state1 = api.setSelectionRange(newSelectionRange);
|
|
28
|
+
if (
|
|
29
|
+
state1.selectedText.length >= state.command.prefix!.length + state.command.suffix!.length &&
|
|
30
|
+
state1.selectedText.startsWith(state.command.prefix!)
|
|
31
|
+
) {
|
|
32
|
+
// Remove
|
|
33
|
+
executeCommand({
|
|
34
|
+
api,
|
|
35
|
+
selectedText: state1.selectedText,
|
|
36
|
+
selection: state.selection,
|
|
37
|
+
prefix: state.command.prefix!,
|
|
38
|
+
suffix: state.command.suffix,
|
|
39
|
+
});
|
|
40
|
+
} else {
|
|
41
|
+
// Add
|
|
42
|
+
state1 = api.setSelectionRange({ start: state.selection.start, end: state.selection.start });
|
|
43
|
+
executeCommand({
|
|
44
|
+
api,
|
|
45
|
+
selectedText: state1.selectedText,
|
|
46
|
+
selection: state.selection,
|
|
47
|
+
prefix: state.command.prefix!,
|
|
48
|
+
suffix: state.command.suffix,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
};
|
package/src/commands/title.tsx
CHANGED
|
@@ -1,6 +1,23 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { ICommand } from './';
|
|
2
|
+
import { ICommand, ExecuteState, TextAreaTextApi } from './';
|
|
3
3
|
import { title1 } from './title1';
|
|
4
|
+
import { selectLine, executeCommand } from '../utils/markdownUtils';
|
|
5
|
+
|
|
6
|
+
export function titleExecute({
|
|
7
|
+
state,
|
|
8
|
+
api,
|
|
9
|
+
prefix,
|
|
10
|
+
suffix = prefix,
|
|
11
|
+
}: {
|
|
12
|
+
state: ExecuteState;
|
|
13
|
+
api: TextAreaTextApi;
|
|
14
|
+
prefix: string;
|
|
15
|
+
suffix?: string;
|
|
16
|
+
}) {
|
|
17
|
+
const newSelectionRange = selectLine({ text: state.text, selection: state.selection });
|
|
18
|
+
const state1 = api.setSelectionRange(newSelectionRange);
|
|
19
|
+
executeCommand({ api, selectedText: state1.selectedText, selection: state.selection, prefix, suffix });
|
|
20
|
+
}
|
|
4
21
|
|
|
5
22
|
export const title: ICommand = {
|
|
6
23
|
...title1,
|
package/src/commands/title1.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 title1: ICommand = {
|
|
6
6
|
name: 'title1',
|
|
7
7
|
keyCommand: 'title1',
|
|
8
8
|
shortcuts: 'ctrlcmd+1',
|
|
9
|
-
|
|
9
|
+
prefix: '# ',
|
|
10
|
+
suffix: '',
|
|
10
11
|
buttonProps: { 'aria-label': 'Insert title1 (ctrl + 1)', title: 'Insert title1 (ctrl + 1)' },
|
|
11
12
|
icon: <div style={{ fontSize: 18, textAlign: 'left' }}>Title 1</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
|
};
|
package/src/commands/title2.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 title2: ICommand = {
|
|
6
6
|
name: 'title2',
|
|
7
7
|
keyCommand: 'title2',
|
|
8
8
|
shortcuts: 'ctrlcmd+2',
|
|
9
|
-
|
|
9
|
+
prefix: '## ',
|
|
10
|
+
suffix: '',
|
|
10
11
|
buttonProps: { 'aria-label': 'Insert title2 (ctrl + 2)', title: 'Insert title2 (ctrl + 2)' },
|
|
11
12
|
icon: <div style={{ fontSize: 16, textAlign: 'left' }}>Title 2</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
|
};
|
package/src/commands/title3.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 title3: ICommand = {
|
|
6
6
|
name: 'title3',
|
|
7
7
|
keyCommand: 'title3',
|
|
8
8
|
shortcuts: 'ctrlcmd+3',
|
|
9
|
-
|
|
9
|
+
prefix: '### ',
|
|
10
|
+
suffix: '',
|
|
10
11
|
buttonProps: { 'aria-label': 'Insert title3 (ctrl + 3)', title: 'Insert title3 (ctrl + 3)' },
|
|
11
12
|
icon: <div style={{ fontSize: 15, textAlign: 'left' }}>Title 3</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
|
};
|
package/src/commands/title4.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 title4: ICommand = {
|
|
6
6
|
name: 'title4',
|
|
7
7
|
keyCommand: 'title4',
|
|
8
8
|
shortcuts: 'ctrlcmd+4',
|
|
9
|
-
|
|
9
|
+
prefix: '#### ',
|
|
10
|
+
suffix: '',
|
|
10
11
|
buttonProps: { 'aria-label': 'Insert title4 (ctrl + 4)', title: 'Insert title4 (ctrl + 4)' },
|
|
11
12
|
icon: <div style={{ fontSize: 14, textAlign: 'left' }}>Title 4</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
|
};
|
package/src/commands/title5.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 title5: ICommand = {
|
|
6
6
|
name: 'title5',
|
|
7
7
|
keyCommand: 'title5',
|
|
8
8
|
shortcuts: 'ctrlcmd+5',
|
|
9
|
-
|
|
9
|
+
prefix: '##### ',
|
|
10
|
+
suffix: '',
|
|
10
11
|
buttonProps: { 'aria-label': 'Insert title5 (ctrl + 5)', title: 'Insert title5 (ctrl + 5)' },
|
|
11
12
|
icon: <div style={{ fontSize: 12, textAlign: 'left' }}>Title 5</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
|
};
|