@dxos/react-ui-editor 0.3.11-main.474ad53 → 0.3.11-main.47fbf79
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/dist/lib/browser/index.mjs +34 -66
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/meta.json +1 -1
- package/dist/types/src/components/TextEditor/MarkdownEditor.stories.d.ts.map +1 -1
- package/dist/types/src/components/Toolbar/Toolbar.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/formatting.d.ts +2 -3
- package/dist/types/src/extensions/markdown/formatting.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/formatting.test.d.ts.map +1 -1
- package/package.json +24 -24
- package/src/components/TextEditor/MarkdownEditor.stories.tsx +1 -1
- package/src/components/Toolbar/Toolbar.stories.tsx +1 -1
- package/src/components/Toolbar/Toolbar.tsx +7 -26
- package/src/extensions/markdown/formatting.test.ts +4 -5
- package/src/extensions/markdown/formatting.ts +34 -73
|
@@ -27,10 +27,11 @@ import { useState, useMemo } from 'react';
|
|
|
27
27
|
// the field only holds true when *all* selected text has the style,
|
|
28
28
|
// or when the selection is a cursor inside such a style.
|
|
29
29
|
export type Formatting = {
|
|
30
|
-
blankLine: boolean;
|
|
31
30
|
// The type of the block at the selection.
|
|
32
31
|
// If multiple different block types are selected, this will hold null.
|
|
33
32
|
blockType:
|
|
33
|
+
| 'paragraph'
|
|
34
|
+
| 'tablecell'
|
|
34
35
|
| 'codeblock'
|
|
35
36
|
| 'heading1'
|
|
36
37
|
| 'heading2'
|
|
@@ -38,11 +39,7 @@ export type Formatting = {
|
|
|
38
39
|
| 'heading4'
|
|
39
40
|
| 'heading5'
|
|
40
41
|
| 'heading6'
|
|
41
|
-
| 'paragraph'
|
|
42
|
-
| 'tablecell'
|
|
43
42
|
| null;
|
|
44
|
-
// Whether all selected text is wrapped in a blockquote.
|
|
45
|
-
blockQuote: boolean;
|
|
46
43
|
// Whether the selected text is strong.
|
|
47
44
|
strong: boolean;
|
|
48
45
|
// Whether the selected text is emphasized.
|
|
@@ -55,6 +52,8 @@ export type Formatting = {
|
|
|
55
52
|
link: boolean;
|
|
56
53
|
// If all selected blocks have the same (innermost) list style, that is indicated here.
|
|
57
54
|
listStyle: null | 'ordered' | 'bullet' | 'task';
|
|
55
|
+
// Whether all selected text is wrapped in a blockquote.
|
|
56
|
+
blockquote: boolean;
|
|
58
57
|
};
|
|
59
58
|
|
|
60
59
|
export const compareFormatting = (a: Formatting, b: Formatting) =>
|
|
@@ -65,7 +64,7 @@ export const compareFormatting = (a: Formatting, b: Formatting) =>
|
|
|
65
64
|
a.code === b.code &&
|
|
66
65
|
a.link === b.link &&
|
|
67
66
|
a.listStyle === b.listStyle &&
|
|
68
|
-
a.
|
|
67
|
+
a.blockquote === b.blockquote;
|
|
69
68
|
|
|
70
69
|
export enum Inline {
|
|
71
70
|
Strong = 0,
|
|
@@ -134,7 +133,6 @@ export const setHeading =
|
|
|
134
133
|
if (!changes.length) {
|
|
135
134
|
return false;
|
|
136
135
|
}
|
|
137
|
-
|
|
138
136
|
dispatch(state.update({ changes, userEvent: 'format.setHeading', scrollIntoView: true }));
|
|
139
137
|
return true;
|
|
140
138
|
};
|
|
@@ -350,32 +348,18 @@ const skipSpaces = (pos: number, doc: Text, dir: -1 | 1, limit?: number) => {
|
|
|
350
348
|
return pos;
|
|
351
349
|
};
|
|
352
350
|
|
|
351
|
+
//
|
|
352
|
+
// Table
|
|
353
|
+
//
|
|
354
|
+
|
|
353
355
|
// TODO(burdon): Define and trigger snippets for codeblock, table, etc.
|
|
354
356
|
const snippets = {
|
|
355
|
-
codeblock: snippet(
|
|
356
|
-
[
|
|
357
|
-
//
|
|
358
|
-
'```#{}',
|
|
359
|
-
'#{}',
|
|
360
|
-
'```',
|
|
361
|
-
].join('\n'),
|
|
362
|
-
),
|
|
357
|
+
codeblock: snippet(['```#{lang}', '#{}', '```'].join('\n')),
|
|
363
358
|
table: snippet(
|
|
364
|
-
[
|
|
365
|
-
//
|
|
366
|
-
'| #{col1} | #{col2} |',
|
|
367
|
-
'| ---- | ---- |',
|
|
368
|
-
'| #{val1} | #{val2} |',
|
|
369
|
-
'| #{val3} | #{val4} |',
|
|
370
|
-
'',
|
|
371
|
-
].join('\n'),
|
|
359
|
+
['| #{col1} | #{col2} |', '| ---- | ---- |', '| #{val1} | #{val2} |', '| #{val3} | #{val4} |'].join('\n'),
|
|
372
360
|
),
|
|
373
361
|
};
|
|
374
362
|
|
|
375
|
-
//
|
|
376
|
-
// Table
|
|
377
|
-
//
|
|
378
|
-
|
|
379
363
|
export const insertTable = (view: EditorView) => {
|
|
380
364
|
const {
|
|
381
365
|
selection: { main },
|
|
@@ -383,7 +367,6 @@ export const insertTable = (view: EditorView) => {
|
|
|
383
367
|
} = view.state;
|
|
384
368
|
const { number } = doc.lineAt(main.anchor);
|
|
385
369
|
const { from } = doc.line(number);
|
|
386
|
-
|
|
387
370
|
snippets.table(view, null, from, from);
|
|
388
371
|
};
|
|
389
372
|
|
|
@@ -573,24 +556,6 @@ export const addList =
|
|
|
573
556
|
}
|
|
574
557
|
|
|
575
558
|
if (!blocks.length) {
|
|
576
|
-
// Insert a new list item if the selection is empty.
|
|
577
|
-
const { from, to } = state.doc.lineAt(state.selection.main.anchor);
|
|
578
|
-
if (from === to) {
|
|
579
|
-
dispatch(
|
|
580
|
-
state.update({
|
|
581
|
-
changes: [
|
|
582
|
-
{
|
|
583
|
-
from,
|
|
584
|
-
insert: type === List.Bullet ? '- ' : type === List.Ordered ? '1. ' : '- [ ] ',
|
|
585
|
-
},
|
|
586
|
-
],
|
|
587
|
-
userEvent: 'format.list.add',
|
|
588
|
-
scrollIntoView: true,
|
|
589
|
-
}),
|
|
590
|
-
);
|
|
591
|
-
return true;
|
|
592
|
-
}
|
|
593
|
-
|
|
594
559
|
return false;
|
|
595
560
|
}
|
|
596
561
|
|
|
@@ -814,7 +779,7 @@ export const addBlockquote = setBlockquote(true);
|
|
|
814
779
|
export const removeBlockquote = setBlockquote(false);
|
|
815
780
|
|
|
816
781
|
export const toggleBlockquote: StateCommand = (target) => {
|
|
817
|
-
return (getFormatting(target.state).
|
|
782
|
+
return (getFormatting(target.state).blockquote ? removeBlockquote : addBlockquote)(target);
|
|
818
783
|
};
|
|
819
784
|
|
|
820
785
|
//
|
|
@@ -1011,38 +976,38 @@ const InlineMarker: { [name: string]: number } = {
|
|
|
1011
976
|
};
|
|
1012
977
|
|
|
1013
978
|
const IgnoreInline = new Set([
|
|
1014
|
-
'Autolink',
|
|
1015
|
-
'CodeMark',
|
|
1016
|
-
'CodeText',
|
|
1017
|
-
'Comment',
|
|
1018
|
-
'EmphasisMark',
|
|
1019
979
|
'Hardbreak',
|
|
1020
|
-
'HeaderMark',
|
|
1021
980
|
'HTMLTag',
|
|
1022
|
-
'
|
|
1023
|
-
'ListMark',
|
|
981
|
+
'Comment',
|
|
1024
982
|
'ProcessingInstruction',
|
|
983
|
+
'Autolink',
|
|
984
|
+
'HeaderMark',
|
|
1025
985
|
'QuoteMark',
|
|
986
|
+
'ListMark',
|
|
987
|
+
'LinkMark',
|
|
988
|
+
'EmphasisMark',
|
|
989
|
+
'CodeMark',
|
|
990
|
+
'CodeText',
|
|
1026
991
|
'StrikethroughMark',
|
|
1027
|
-
'SubscriptMark',
|
|
1028
|
-
'SuperscriptMark',
|
|
1029
992
|
'TaskMarker',
|
|
993
|
+
'SuperscriptMark',
|
|
994
|
+
'SubscriptMark',
|
|
1030
995
|
]);
|
|
1031
996
|
|
|
1032
997
|
const Textblocks: { [name: string]: NonNullable<Formatting['blockType']> } = {
|
|
998
|
+
Paragraph: 'paragraph',
|
|
999
|
+
Task: 'paragraph',
|
|
1000
|
+
CodeBlock: 'codeblock',
|
|
1001
|
+
FencedCode: 'codeblock',
|
|
1033
1002
|
ATXHeading1: 'heading1',
|
|
1034
1003
|
ATXHeading2: 'heading2',
|
|
1035
1004
|
ATXHeading3: 'heading3',
|
|
1036
1005
|
ATXHeading4: 'heading4',
|
|
1037
1006
|
ATXHeading5: 'heading5',
|
|
1038
1007
|
ATXHeading6: 'heading6',
|
|
1039
|
-
CodeBlock: 'codeblock',
|
|
1040
|
-
FencedCode: 'codeblock',
|
|
1041
|
-
Paragraph: 'paragraph',
|
|
1042
1008
|
SetextHeading1: 'heading1',
|
|
1043
1009
|
SetextHeading2: 'heading2',
|
|
1044
1010
|
TableCell: 'tablecell',
|
|
1045
|
-
Task: 'paragraph',
|
|
1046
1011
|
};
|
|
1047
1012
|
|
|
1048
1013
|
/**
|
|
@@ -1056,7 +1021,7 @@ export const getFormatting = (state: EditorState): Formatting => {
|
|
|
1056
1021
|
// null = no text seen, true = all text had the mark, false = saw text without it.
|
|
1057
1022
|
const inline: (boolean | null)[] = [null, null, null, null];
|
|
1058
1023
|
let link: boolean = false;
|
|
1059
|
-
let
|
|
1024
|
+
let blockquote: boolean | null = null;
|
|
1060
1025
|
// False indicates mixed list styles
|
|
1061
1026
|
let listStyle: Formatting['listStyle'] | null | false = null;
|
|
1062
1027
|
|
|
@@ -1178,10 +1143,10 @@ export const getFormatting = (state: EditorState): Formatting => {
|
|
|
1178
1143
|
hasList = stack[i] === 'TaskList' ? 'task' : stack[i] === 'BulletList' ? 'bullet' : 'ordered';
|
|
1179
1144
|
}
|
|
1180
1145
|
}
|
|
1181
|
-
if (
|
|
1182
|
-
|
|
1183
|
-
} else if (!hasQuote &&
|
|
1184
|
-
|
|
1146
|
+
if (blockquote === null) {
|
|
1147
|
+
blockquote = hasQuote;
|
|
1148
|
+
} else if (!hasQuote && blockquote) {
|
|
1149
|
+
blockquote = false;
|
|
1185
1150
|
}
|
|
1186
1151
|
if (listStyle === null) {
|
|
1187
1152
|
listStyle = hasList;
|
|
@@ -1199,18 +1164,14 @@ export const getFormatting = (state: EditorState): Formatting => {
|
|
|
1199
1164
|
});
|
|
1200
1165
|
}
|
|
1201
1166
|
|
|
1202
|
-
const { from, to } = state.doc.lineAt(selection.main.anchor);
|
|
1203
|
-
const blankLine = from === to;
|
|
1204
|
-
|
|
1205
1167
|
return {
|
|
1206
|
-
blankLine,
|
|
1207
1168
|
blockType: blockType || null,
|
|
1208
|
-
blockQuote: blockQuote ?? false,
|
|
1209
|
-
code: inline[Inline.Code] ?? false,
|
|
1210
|
-
emphasis: inline[Inline.Emphasis] ?? false,
|
|
1211
1169
|
strong: inline[Inline.Strong] ?? false,
|
|
1170
|
+
emphasis: inline[Inline.Emphasis] ?? false,
|
|
1171
|
+
code: inline[Inline.Code] ?? false,
|
|
1212
1172
|
strikethrough: inline[Inline.Strikethrough] ?? false,
|
|
1213
1173
|
link,
|
|
1174
|
+
blockquote: blockquote ?? false,
|
|
1214
1175
|
listStyle: listStyle || null,
|
|
1215
1176
|
};
|
|
1216
1177
|
};
|