@eccenca/gui-elements 24.0.1 → 24.1.0-featureimprovepublishingprocesscmem6356.0
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/CHANGELOG.md +82 -0
- package/dist/cjs/cmem/ActivityControl/ActivityControlWidget.js +7 -2
- package/dist/cjs/cmem/ActivityControl/ActivityControlWidget.js.map +1 -1
- package/dist/cjs/cmem/react-flow/StickyNoteModal/StickyNoteModal.js +3 -3
- package/dist/cjs/cmem/react-flow/StickyNoteModal/StickyNoteModal.js.map +1 -1
- package/dist/cjs/components/AutoSuggestion/AutoSuggestion.js +13 -3
- package/dist/cjs/components/AutoSuggestion/AutoSuggestion.js.map +1 -1
- package/dist/cjs/components/AutoSuggestion/ExtendedCodeEditor.js +3 -3
- package/dist/cjs/components/AutoSuggestion/ExtendedCodeEditor.js.map +1 -1
- package/dist/cjs/components/AutocompleteField/AutoCompleteField.js +4 -2
- package/dist/cjs/components/AutocompleteField/AutoCompleteField.js.map +1 -1
- package/dist/cjs/components/Card/CardActions.js +2 -1
- package/dist/cjs/components/Card/CardActions.js.map +1 -1
- package/dist/cjs/components/Card/CardContent.js +4 -6
- package/dist/cjs/components/Card/CardContent.js.map +1 -1
- package/dist/cjs/components/ContentGroup/ContentGroup.js +95 -0
- package/dist/cjs/components/ContentGroup/ContentGroup.js.map +1 -0
- package/dist/cjs/components/Dialog/SimpleDialog.js +3 -3
- package/dist/cjs/components/Dialog/SimpleDialog.js.map +1 -1
- package/dist/cjs/components/Icon/canonicalIconNames.js +12 -0
- package/dist/cjs/components/Icon/canonicalIconNames.js.map +1 -1
- package/dist/cjs/components/Label/Label.js +8 -3
- package/dist/cjs/components/Label/Label.js.map +1 -1
- package/dist/cjs/components/Menu/MenuItem.js +3 -2
- package/dist/cjs/components/Menu/MenuItem.js.map +1 -1
- package/dist/cjs/components/OverviewItem/OverviewItem.js +5 -2
- package/dist/cjs/components/OverviewItem/OverviewItem.js.map +1 -1
- package/dist/cjs/components/OverviewItem/OverviewItemList.js +2 -2
- package/dist/cjs/components/OverviewItem/OverviewItemList.js.map +1 -1
- package/dist/cjs/components/Switch/Switch.js +6 -4
- package/dist/cjs/components/Switch/Switch.js.map +1 -1
- package/dist/cjs/components/Tag/TagList.js +1 -1
- package/dist/cjs/components/Tag/TagList.js.map +1 -1
- package/dist/cjs/components/TextField/SearchField.js +19 -2
- package/dist/cjs/components/TextField/SearchField.js.map +1 -1
- package/dist/cjs/components/Typography/OverflowText.js +1 -1
- package/dist/cjs/components/Typography/OverflowText.js.map +1 -1
- package/dist/cjs/components/index.js +1 -0
- package/dist/cjs/components/index.js.map +1 -1
- package/dist/cjs/extensions/codemirror/CodeMirror.js +93 -11
- package/dist/cjs/extensions/codemirror/CodeMirror.js.map +1 -1
- package/dist/cjs/extensions/codemirror/debouncedLinter.js +18 -0
- package/dist/cjs/extensions/codemirror/debouncedLinter.js.map +1 -0
- package/dist/cjs/extensions/codemirror/hooks/useCodemirrorModeExtension.hooks.js +1 -1
- package/dist/cjs/extensions/codemirror/hooks/useCodemirrorModeExtension.hooks.js.map +1 -1
- package/dist/cjs/extensions/codemirror/linters/jsLinter.js +36 -0
- package/dist/cjs/extensions/codemirror/linters/jsLinter.js.map +1 -0
- package/dist/cjs/extensions/codemirror/linters/turtleLinter.js +81 -0
- package/dist/cjs/extensions/codemirror/linters/turtleLinter.js.map +1 -0
- package/dist/cjs/extensions/codemirror/tests/codemirrorTestHelper.js +4 -1
- package/dist/cjs/extensions/codemirror/tests/codemirrorTestHelper.js.map +1 -1
- package/dist/cjs/extensions/codemirror/toolbars/commands/markdown.command.js +278 -0
- package/dist/cjs/extensions/codemirror/toolbars/commands/markdown.command.js.map +1 -0
- package/dist/cjs/extensions/codemirror/toolbars/markdown.toolbar.js +47 -0
- package/dist/cjs/extensions/codemirror/toolbars/markdown.toolbar.js.map +1 -0
- package/dist/cjs/extensions/codemirror/types.js +3 -0
- package/dist/cjs/extensions/codemirror/types.js.map +1 -0
- package/dist/cjs/extensions/react-flow/nodes/NodeContent.js +140 -41
- package/dist/cjs/extensions/react-flow/nodes/NodeContent.js.map +1 -1
- package/dist/cjs/extensions/react-flow/nodes/nodeUtils.js +5 -6
- package/dist/cjs/extensions/react-flow/nodes/nodeUtils.js.map +1 -1
- package/dist/esm/cmem/ActivityControl/ActivityControlWidget.js +7 -2
- package/dist/esm/cmem/ActivityControl/ActivityControlWidget.js.map +1 -1
- package/dist/esm/cmem/react-flow/StickyNoteModal/StickyNoteModal.js +4 -4
- package/dist/esm/cmem/react-flow/StickyNoteModal/StickyNoteModal.js.map +1 -1
- package/dist/esm/components/AutoSuggestion/AutoSuggestion.js +13 -3
- package/dist/esm/components/AutoSuggestion/AutoSuggestion.js.map +1 -1
- package/dist/esm/components/AutoSuggestion/ExtendedCodeEditor.js +14 -3
- package/dist/esm/components/AutoSuggestion/ExtendedCodeEditor.js.map +1 -1
- package/dist/esm/components/AutocompleteField/AutoCompleteField.js +4 -3
- package/dist/esm/components/AutocompleteField/AutoCompleteField.js.map +1 -1
- package/dist/esm/components/Card/CardActions.js +2 -1
- package/dist/esm/components/Card/CardActions.js.map +1 -1
- package/dist/esm/components/Card/CardContent.js +4 -5
- package/dist/esm/components/Card/CardContent.js.map +1 -1
- package/dist/esm/components/ContentGroup/ContentGroup.js +100 -0
- package/dist/esm/components/ContentGroup/ContentGroup.js.map +1 -0
- package/dist/esm/components/Dialog/SimpleDialog.js +4 -4
- package/dist/esm/components/Dialog/SimpleDialog.js.map +1 -1
- package/dist/esm/components/Icon/canonicalIconNames.js +12 -0
- package/dist/esm/components/Icon/canonicalIconNames.js.map +1 -1
- package/dist/esm/components/Label/Label.js +8 -3
- package/dist/esm/components/Label/Label.js.map +1 -1
- package/dist/esm/components/Menu/MenuItem.js +3 -2
- package/dist/esm/components/Menu/MenuItem.js.map +1 -1
- package/dist/esm/components/OverviewItem/OverviewItem.js +5 -2
- package/dist/esm/components/OverviewItem/OverviewItem.js.map +1 -1
- package/dist/esm/components/OverviewItem/OverviewItemList.js +2 -2
- package/dist/esm/components/OverviewItem/OverviewItemList.js.map +1 -1
- package/dist/esm/components/Switch/Switch.js +7 -5
- package/dist/esm/components/Switch/Switch.js.map +1 -1
- package/dist/esm/components/Tag/TagList.js +1 -1
- package/dist/esm/components/Tag/TagList.js.map +1 -1
- package/dist/esm/components/TextField/SearchField.js +35 -2
- package/dist/esm/components/TextField/SearchField.js.map +1 -1
- package/dist/esm/components/Typography/OverflowText.js +1 -1
- package/dist/esm/components/Typography/OverflowText.js.map +1 -1
- package/dist/esm/components/index.js +1 -0
- package/dist/esm/components/index.js.map +1 -1
- package/dist/esm/extensions/codemirror/CodeMirror.js +94 -13
- package/dist/esm/extensions/codemirror/CodeMirror.js.map +1 -1
- package/dist/esm/extensions/codemirror/debouncedLinter.js +15 -0
- package/dist/esm/extensions/codemirror/debouncedLinter.js.map +1 -0
- package/dist/esm/extensions/codemirror/hooks/useCodemirrorModeExtension.hooks.js +1 -1
- package/dist/esm/extensions/codemirror/hooks/useCodemirrorModeExtension.hooks.js.map +1 -1
- package/dist/esm/extensions/codemirror/linters/jsLinter.js +32 -0
- package/dist/esm/extensions/codemirror/linters/jsLinter.js.map +1 -0
- package/dist/esm/extensions/codemirror/linters/turtleLinter.js +77 -0
- package/dist/esm/extensions/codemirror/linters/turtleLinter.js.map +1 -0
- package/dist/esm/extensions/codemirror/tests/codemirrorTestHelper.js +4 -0
- package/dist/esm/extensions/codemirror/tests/codemirrorTestHelper.js.map +1 -1
- package/dist/esm/extensions/codemirror/toolbars/commands/markdown.command.js +283 -0
- package/dist/esm/extensions/codemirror/toolbars/commands/markdown.command.js.map +1 -0
- package/dist/esm/extensions/codemirror/toolbars/markdown.toolbar.js +41 -0
- package/dist/esm/extensions/codemirror/toolbars/markdown.toolbar.js.map +1 -0
- package/dist/esm/extensions/codemirror/types.js +2 -0
- package/dist/esm/extensions/codemirror/types.js.map +1 -0
- package/dist/esm/extensions/react-flow/nodes/NodeContent.js +149 -48
- package/dist/esm/extensions/react-flow/nodes/NodeContent.js.map +1 -1
- package/dist/esm/extensions/react-flow/nodes/nodeUtils.js +5 -6
- package/dist/esm/extensions/react-flow/nodes/nodeUtils.js.map +1 -1
- package/dist/types/cmem/ActivityControl/ActivityControlWidget.d.ts +1 -1
- package/dist/types/cmem/react-flow/StickyNoteModal/StickyNoteModal.d.ts +5 -1
- package/dist/types/components/AutoSuggestion/ExtendedCodeEditor.d.ts +11 -6
- package/dist/types/components/Card/CardActions.d.ts +5 -1
- package/dist/types/components/Card/CardContent.d.ts +1 -2
- package/dist/types/components/ContentGroup/ContentGroup.d.ts +78 -0
- package/dist/types/components/Dialog/SimpleDialog.d.ts +4 -1
- package/dist/types/components/Icon/canonicalIconNames.d.ts +12 -0
- package/dist/types/components/Label/Label.d.ts +7 -1
- package/dist/types/components/Menu/MenuItem.d.ts +8 -1
- package/dist/types/components/OverviewItem/OverviewItem.d.ts +13 -1
- package/dist/types/components/OverviewItem/OverviewItemList.d.ts +3 -2
- package/dist/types/components/ProgressBar/ProgressBar.d.ts +2 -2
- package/dist/types/components/Structure/TitleSubsection.d.ts +7 -0
- package/dist/types/components/Switch/Switch.d.ts +3 -3
- package/dist/types/components/Tabs/Tab.d.ts +14 -0
- package/dist/types/components/TextField/SearchField.d.ts +1 -1
- package/dist/types/components/Typography/OverflowText.d.ts +23 -2
- package/dist/types/components/index.d.ts +1 -0
- package/dist/types/extensions/codemirror/CodeMirror.d.ts +32 -5
- package/dist/types/extensions/codemirror/debouncedLinter.d.ts +4 -0
- package/dist/types/extensions/codemirror/linters/jsLinter.d.ts +5 -0
- package/dist/types/extensions/codemirror/linters/turtleLinter.d.ts +5 -0
- package/dist/types/extensions/codemirror/tests/codemirrorTestHelper.d.ts +1 -0
- package/dist/types/extensions/codemirror/toolbars/commands/markdown.command.d.ts +55 -0
- package/dist/types/extensions/codemirror/toolbars/markdown.toolbar.d.ts +12 -0
- package/dist/types/extensions/codemirror/types.d.ts +5 -0
- package/dist/types/extensions/react-flow/nodes/NodeContent.d.ts +18 -4
- package/dist/types/extensions/react-flow/nodes/nodeUtils.d.ts +7 -6
- package/package.json +50 -47
- package/src/cmem/ActivityControl/ActivityControlWidget.tsx +5 -2
- package/src/cmem/react-flow/StickyNoteModal/StickyNoteModal.tsx +16 -2
- package/src/cmem/react-flow/configuration/_colors-graph.scss +4 -1
- package/src/cmem/react-flow/configuration/_colors-workflow.scss +3 -0
- package/src/components/AutoSuggestion/AutoSuggestion.tsx +14 -3
- package/src/components/AutoSuggestion/ExtendedCodeEditor.tsx +29 -6
- package/src/components/AutocompleteField/AutoCompleteField.tsx +5 -3
- package/src/components/Card/CardActions.tsx +6 -0
- package/src/components/Card/CardContent.tsx +8 -4
- package/src/components/Card/card.scss +15 -0
- package/src/components/CodeAutocompleteField/CodeAutocompleteField.stories.tsx +3 -2
- package/src/components/ContentGroup/ContentGroup.stories.tsx +47 -0
- package/src/components/ContentGroup/ContentGroup.tsx +256 -0
- package/src/components/ContentGroup/_contentgroup.scss +56 -0
- package/src/components/ContextOverlay/ContextOverlay.stories.tsx +15 -4
- package/src/components/Depiction/depiction.scss +7 -0
- package/src/components/Dialog/SimpleDialog.tsx +9 -2
- package/src/components/Dialog/stories/AlertDialog.stories.tsx +5 -1
- package/src/components/Dialog/stories/Modal.stories.tsx +4 -2
- package/src/components/Dialog/stories/SimpleDialog.stories.tsx +5 -2
- package/src/components/Icon/canonicalIconNames.tsx +12 -0
- package/src/components/Label/Label.stories.tsx +2 -1
- package/src/components/Label/Label.tsx +17 -1
- package/src/components/Label/label.scss +5 -1
- package/src/components/Menu/MenuItem.tsx +27 -1
- package/src/components/Menu/menu.scss +1 -0
- package/src/components/OverviewItem/OverviewItem.tsx +24 -1
- package/src/components/OverviewItem/OverviewItemList.tsx +3 -2
- package/src/components/OverviewItem/overviewitem.scss +4 -1
- package/src/components/OverviewItem/stories/OverviewItem.stories.tsx +6 -12
- package/src/components/Select/Select.stories.tsx +4 -1
- package/src/components/Switch/Switch.tsx +27 -8
- package/src/components/Tag/TagList.tsx +2 -2
- package/src/components/TextField/SearchField.tsx +37 -9
- package/src/components/TextField/stories/SearchField.stories.tsx +15 -1
- package/src/components/TextField/stories/TextField.stories.tsx +2 -1
- package/src/components/TextField/textfield.scss +17 -3
- package/src/components/Typography/OverflowText.tsx +24 -3
- package/src/components/Typography/stories/OverflowText.stories.tsx +33 -0
- package/src/components/index.scss +1 -0
- package/src/components/index.ts +1 -0
- package/src/extensions/codemirror/CodeMirror.stories.tsx +19 -1
- package/src/extensions/codemirror/CodeMirror.tsx +154 -16
- package/src/extensions/codemirror/_codemirror.scss +130 -1
- package/src/extensions/codemirror/debouncedLinter.ts +26 -0
- package/src/extensions/codemirror/hooks/useCodemirrorModeExtension.hooks.ts +1 -1
- package/src/extensions/codemirror/linters/jsLinter.ts +38 -0
- package/src/extensions/codemirror/linters/turtleLinter.ts +102 -0
- package/src/extensions/codemirror/tests/codemirrorTestHelper.ts +4 -0
- package/src/extensions/codemirror/toolbars/commands/markdown.command.ts +340 -0
- package/src/extensions/codemirror/toolbars/markdown.toolbar.tsx +117 -0
- package/src/extensions/codemirror/types.ts +7 -0
- package/src/extensions/react-flow/_config.scss +1 -0
- package/src/extensions/react-flow/nodes/NodeContent.tsx +170 -52
- package/src/extensions/react-flow/nodes/_nodes.scss +71 -35
- package/src/extensions/react-flow/nodes/nodeUtils.tsx +16 -14
- package/src/extensions/react-flow/nodes/stories/NodeContent.stories.tsx +51 -12
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
import { type ChangeSpec, EditorSelection } from "@codemirror/state";
|
|
2
|
+
import { EditorView } from "codemirror";
|
|
3
|
+
|
|
4
|
+
import { ValidIconName } from "../../../../components/Icon/canonicalIconNames";
|
|
5
|
+
|
|
6
|
+
enum Commands {
|
|
7
|
+
header1 = "Heading 1",
|
|
8
|
+
header2 = "Heading 2",
|
|
9
|
+
header3 = "Heading 3",
|
|
10
|
+
header4 = "Heading 4",
|
|
11
|
+
header5 = "Heading 5",
|
|
12
|
+
header6 = "Heading 6",
|
|
13
|
+
codeBlock = "Code block",
|
|
14
|
+
quote = "Block quote",
|
|
15
|
+
bold = "Bold",
|
|
16
|
+
italic = "Italic",
|
|
17
|
+
strike = "StrikeThrough",
|
|
18
|
+
inlineCode = "Inline code",
|
|
19
|
+
unorderedList = "Unordered list",
|
|
20
|
+
orderedList = "Ordered list",
|
|
21
|
+
todoList = "Todo list",
|
|
22
|
+
link = "Link",
|
|
23
|
+
image = "Image",
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
type formatConfig = { start: number; startDelimiter: string; stop?: number; endDelimiter?: string };
|
|
27
|
+
type headerLevels = 1 | 2 | 3 | 4 | 5 | 6;
|
|
28
|
+
type ListType = "ul" | "ol" | "todo";
|
|
29
|
+
|
|
30
|
+
//contains all utilities for markdown toolbar
|
|
31
|
+
export default class MarkdownCommand {
|
|
32
|
+
private view: EditorView | null = null;
|
|
33
|
+
|
|
34
|
+
//list of supported commands as well as the valid icon names.
|
|
35
|
+
public static commands = {
|
|
36
|
+
paragraphs: [
|
|
37
|
+
Commands.header1,
|
|
38
|
+
Commands.header2,
|
|
39
|
+
Commands.header3,
|
|
40
|
+
Commands.header4,
|
|
41
|
+
Commands.header5,
|
|
42
|
+
Commands.header6,
|
|
43
|
+
Commands.quote,
|
|
44
|
+
Commands.codeBlock,
|
|
45
|
+
],
|
|
46
|
+
basic: [
|
|
47
|
+
{ title: Commands.bold, icon: "operation-format-text-bold" },
|
|
48
|
+
{ title: Commands.italic, icon: "operation-format-text-italic" },
|
|
49
|
+
{ title: Commands.strike, icon: "operation-format-text-strikethrough" },
|
|
50
|
+
{ title: Commands.inlineCode, icon: "operation-format-text-code" },
|
|
51
|
+
] as { title: Commands; icon: ValidIconName }[],
|
|
52
|
+
lists: [
|
|
53
|
+
{ title: Commands.unorderedList, icon: "operation-format-list-bullet", moniker: "ul" },
|
|
54
|
+
{ title: Commands.orderedList, icon: "operation-format-list-numbered", moniker: "ol" },
|
|
55
|
+
{ title: Commands.todoList, icon: "operation-format-list-checked", moniker: "todo" },
|
|
56
|
+
] as { title: Commands; icon: ValidIconName; moniker: string }[],
|
|
57
|
+
attachments: [
|
|
58
|
+
{ title: Commands.link, icon: "operation-link" },
|
|
59
|
+
{ title: Commands.image, icon: "item-image" },
|
|
60
|
+
] as { title: Commands; icon: ValidIconName }[],
|
|
61
|
+
} as const;
|
|
62
|
+
|
|
63
|
+
constructor(view: EditorView) {
|
|
64
|
+
this.view = view;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Supported list types are ol, ul, todo.
|
|
69
|
+
* utility helps to determine which at the start of the line
|
|
70
|
+
*/
|
|
71
|
+
private getListTypeOfLine = (text: string): [ListType, number?] | undefined => {
|
|
72
|
+
if (!text) return;
|
|
73
|
+
text = text?.trimStart();
|
|
74
|
+
|
|
75
|
+
if (text.startsWith("- ")) {
|
|
76
|
+
if (text.startsWith("- [ ] ") || text.startsWith("- [x] ")) return ["todo"];
|
|
77
|
+
return ["ul"];
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const v = text.match(/^(\d+)\. /);
|
|
81
|
+
|
|
82
|
+
return v ? ["ol", Number.parseInt(v[1], 10)] : undefined;
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
//inserts the list delimiters of "-", "- [ ]" and "{number}."
|
|
86
|
+
private createListDelimiter(text: string, type: string, orderedList: { currentIndex: number }) {
|
|
87
|
+
return text.replace(/^(( *)(-( \[[x ]])?|\d+\.) )?/, (...args) => {
|
|
88
|
+
const { space = "" } = args[args.length - 1];
|
|
89
|
+
|
|
90
|
+
let newFlag = "- ";
|
|
91
|
+
|
|
92
|
+
if (type === "ol") {
|
|
93
|
+
newFlag = `${orderedList.currentIndex}. `;
|
|
94
|
+
orderedList.currentIndex++;
|
|
95
|
+
} else if (type === "todo") {
|
|
96
|
+
newFlag = "- [ ] ";
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return space + newFlag;
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
//factory for different list types.
|
|
104
|
+
private createList = (type: ListType) => {
|
|
105
|
+
if (!this.view) return;
|
|
106
|
+
const view = this.view;
|
|
107
|
+
const doc = view.state.doc;
|
|
108
|
+
|
|
109
|
+
const orderedList = { currentIndex: 1 };
|
|
110
|
+
|
|
111
|
+
view.dispatch(
|
|
112
|
+
view.state.changeByRange((range) => {
|
|
113
|
+
const text = doc.slice(range.from, range.to);
|
|
114
|
+
const changes: ChangeSpec[] = [];
|
|
115
|
+
|
|
116
|
+
let selectionStart: number = range.from;
|
|
117
|
+
let selectionLength: number = range.to - range.from;
|
|
118
|
+
|
|
119
|
+
Array.from({ length: text.lines }).forEach((_, index) => {
|
|
120
|
+
const line = doc.line(doc.lineAt(range.from).number + index);
|
|
121
|
+
|
|
122
|
+
const currentListType = this.getListTypeOfLine(line.text);
|
|
123
|
+
|
|
124
|
+
if (currentListType && currentListType[0] === type) {
|
|
125
|
+
if (currentListType[0] === "ol" && currentListType[1]) {
|
|
126
|
+
orderedList.currentIndex = currentListType[1];
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
const content = this.createListDelimiter(line.text, type, orderedList);
|
|
132
|
+
|
|
133
|
+
const diffLength = content.length - line.length;
|
|
134
|
+
|
|
135
|
+
changes.push({
|
|
136
|
+
from: line.from,
|
|
137
|
+
to: line.to,
|
|
138
|
+
insert: content,
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
if (index === 0) {
|
|
142
|
+
selectionStart = selectionStart + diffLength;
|
|
143
|
+
} else {
|
|
144
|
+
selectionLength = selectionLength + diffLength;
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
return {
|
|
149
|
+
changes,
|
|
150
|
+
range: EditorSelection.range(selectionStart, selectionStart + selectionLength),
|
|
151
|
+
};
|
|
152
|
+
})
|
|
153
|
+
);
|
|
154
|
+
|
|
155
|
+
view.focus();
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
private enforceCursorFocus = (cursorPosition: number) => {
|
|
159
|
+
if (!this.view) return;
|
|
160
|
+
const view = this.view;
|
|
161
|
+
setTimeout(() => {
|
|
162
|
+
view.dispatch({
|
|
163
|
+
selection: EditorSelection.cursor(cursorPosition),
|
|
164
|
+
});
|
|
165
|
+
view.focus();
|
|
166
|
+
}, 50);
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
//supported headers from h1-h6, h6 being the smallest
|
|
170
|
+
private createHeading = (level: headerLevels) => {
|
|
171
|
+
if (!this.view) return;
|
|
172
|
+
const view = this.view;
|
|
173
|
+
const state = view.state;
|
|
174
|
+
|
|
175
|
+
const flags = "#".repeat(level) + " ";
|
|
176
|
+
|
|
177
|
+
let lastCursorPosition = 0;
|
|
178
|
+
|
|
179
|
+
view.dispatch(
|
|
180
|
+
state.changeByRange((range) => {
|
|
181
|
+
const line = state.doc.lineAt(range.from);
|
|
182
|
+
|
|
183
|
+
const content = line.text.replace(/^((#+) )?/, flags);
|
|
184
|
+
|
|
185
|
+
const diffLength = content.length - line.length;
|
|
186
|
+
lastCursorPosition = line.to + diffLength;
|
|
187
|
+
return {
|
|
188
|
+
changes: {
|
|
189
|
+
from: line.from,
|
|
190
|
+
to: line.to,
|
|
191
|
+
insert: content,
|
|
192
|
+
},
|
|
193
|
+
range: EditorSelection.range(range.anchor + diffLength, range.head + diffLength),
|
|
194
|
+
};
|
|
195
|
+
})
|
|
196
|
+
);
|
|
197
|
+
|
|
198
|
+
this.enforceCursorFocus(lastCursorPosition);
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
private applyFormatting = ({
|
|
202
|
+
start,
|
|
203
|
+
startDelimiter,
|
|
204
|
+
endDelimiter = startDelimiter,
|
|
205
|
+
stop = start,
|
|
206
|
+
}: formatConfig) => {
|
|
207
|
+
if (!this.view) return;
|
|
208
|
+
const view = this.view;
|
|
209
|
+
const { from, to } = view.state.selection.main;
|
|
210
|
+
const text = view.state.sliceDoc(from, to);
|
|
211
|
+
view.dispatch(
|
|
212
|
+
view.state.changeByRange((range) => {
|
|
213
|
+
return {
|
|
214
|
+
changes: [{ from: range.from, to: range.to, insert: `${startDelimiter}${text}${endDelimiter}` }],
|
|
215
|
+
range: EditorSelection.range(range.from + start, range.to + stop),
|
|
216
|
+
};
|
|
217
|
+
})
|
|
218
|
+
);
|
|
219
|
+
view.focus();
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
private applyAttachment = (type: Commands.link | Commands.image) => {
|
|
223
|
+
if (!this.view) return;
|
|
224
|
+
const view = this.view;
|
|
225
|
+
const { state } = view;
|
|
226
|
+
const isImageAttachmentType = type === Commands.image;
|
|
227
|
+
|
|
228
|
+
const { doc } = state;
|
|
229
|
+
|
|
230
|
+
view.dispatch(
|
|
231
|
+
state.changeByRange((range) => {
|
|
232
|
+
const { from, to } = range;
|
|
233
|
+
|
|
234
|
+
const text = doc.sliceString(from, to);
|
|
235
|
+
|
|
236
|
+
const link = `${isImageAttachmentType ? `!` : ""}[${text}]()`;
|
|
237
|
+
|
|
238
|
+
const cursor = from + (text.length ? 3 + text.length : 1 + Number(isImageAttachmentType));
|
|
239
|
+
|
|
240
|
+
return {
|
|
241
|
+
changes: [
|
|
242
|
+
{
|
|
243
|
+
from,
|
|
244
|
+
to,
|
|
245
|
+
insert: link,
|
|
246
|
+
},
|
|
247
|
+
],
|
|
248
|
+
range: EditorSelection.range(cursor, cursor),
|
|
249
|
+
};
|
|
250
|
+
})
|
|
251
|
+
);
|
|
252
|
+
|
|
253
|
+
view.focus();
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
private applyQuoteFormatting = () => {
|
|
257
|
+
if (!this.view) return;
|
|
258
|
+
const view = this.view;
|
|
259
|
+
const { state } = view;
|
|
260
|
+
const { doc } = state;
|
|
261
|
+
|
|
262
|
+
let lastCursorPosition = 0;
|
|
263
|
+
|
|
264
|
+
view.dispatch(
|
|
265
|
+
view.state.changeByRange((range) => {
|
|
266
|
+
const startLine = doc.lineAt(range.from);
|
|
267
|
+
|
|
268
|
+
const text = doc.slice(range.from, range.to);
|
|
269
|
+
|
|
270
|
+
const lineCount = text.lines;
|
|
271
|
+
|
|
272
|
+
const changes: ChangeSpec[] = [];
|
|
273
|
+
|
|
274
|
+
let selectionStart: number = range.from;
|
|
275
|
+
let selectionLength: number = range.to - range.from;
|
|
276
|
+
|
|
277
|
+
new Array(lineCount).fill(0).forEach((_, index) => {
|
|
278
|
+
const line = doc.line(startLine.number + index);
|
|
279
|
+
|
|
280
|
+
if (line.text.startsWith("> ")) {
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
changes.push({
|
|
284
|
+
from: line.from,
|
|
285
|
+
insert: "> ",
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
if (index === 0) {
|
|
289
|
+
selectionStart = selectionStart + 2;
|
|
290
|
+
} else {
|
|
291
|
+
selectionLength += 2;
|
|
292
|
+
}
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
lastCursorPosition = selectionStart + selectionLength;
|
|
296
|
+
|
|
297
|
+
return {
|
|
298
|
+
changes,
|
|
299
|
+
range: EditorSelection.range(selectionStart, selectionStart + selectionLength),
|
|
300
|
+
};
|
|
301
|
+
})
|
|
302
|
+
);
|
|
303
|
+
this.enforceCursorFocus(lastCursorPosition);
|
|
304
|
+
};
|
|
305
|
+
|
|
306
|
+
executeCommand = (command: Commands): true | void => {
|
|
307
|
+
switch (command) {
|
|
308
|
+
case Commands.bold:
|
|
309
|
+
return this.applyFormatting({ start: 2, startDelimiter: "**" });
|
|
310
|
+
case Commands.italic:
|
|
311
|
+
return this.applyFormatting({ start: 1, startDelimiter: "*" });
|
|
312
|
+
case Commands.codeBlock:
|
|
313
|
+
return this.applyFormatting({ start: 3, startDelimiter: "```\n", endDelimiter: "\n```" });
|
|
314
|
+
case Commands.strike:
|
|
315
|
+
return this.applyFormatting({ start: 2, startDelimiter: "~~" });
|
|
316
|
+
case Commands.inlineCode:
|
|
317
|
+
return this.applyFormatting({ start: 1, startDelimiter: "`" });
|
|
318
|
+
case Commands.header1:
|
|
319
|
+
case Commands.header2:
|
|
320
|
+
case Commands.header3:
|
|
321
|
+
case Commands.header4:
|
|
322
|
+
case Commands.header5:
|
|
323
|
+
case Commands.header6:
|
|
324
|
+
return this.createHeading(Number(command.slice(-1)) as headerLevels);
|
|
325
|
+
case Commands.unorderedList:
|
|
326
|
+
case Commands.orderedList:
|
|
327
|
+
case Commands.todoList:
|
|
328
|
+
return this.createList(
|
|
329
|
+
MarkdownCommand.commands.lists.find((l) => l.title === command)?.moniker as ListType
|
|
330
|
+
);
|
|
331
|
+
case Commands.image:
|
|
332
|
+
case Commands.link:
|
|
333
|
+
return this.applyAttachment(command);
|
|
334
|
+
case Commands.quote:
|
|
335
|
+
return this.applyQuoteFormatting();
|
|
336
|
+
default:
|
|
337
|
+
return; //do nothing;
|
|
338
|
+
}
|
|
339
|
+
};
|
|
340
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { EditorView } from "codemirror";
|
|
3
|
+
|
|
4
|
+
import { Button } from "../../../components/Button/Button";
|
|
5
|
+
import { ContextMenu } from "../../../components/ContextOverlay";
|
|
6
|
+
import { Icon, IconButton } from "../../../components/Icon";
|
|
7
|
+
import { MenuItem } from "../../../components/Menu";
|
|
8
|
+
import { Spacing } from "../../../components/Separation/Spacing";
|
|
9
|
+
import { Toolbar, ToolbarSection } from "../../../components/Toolbar";
|
|
10
|
+
|
|
11
|
+
import MarkdownCommand from "./commands/markdown.command";
|
|
12
|
+
|
|
13
|
+
interface MarkdownToolbarProps {
|
|
14
|
+
view?: EditorView;
|
|
15
|
+
togglePreviewStatus: () => void;
|
|
16
|
+
showPreview: boolean;
|
|
17
|
+
translate: (key: string) => string | false;
|
|
18
|
+
disabled?: boolean;
|
|
19
|
+
readonly?: boolean;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export const MarkdownToolbar: React.FC<MarkdownToolbarProps> = ({
|
|
23
|
+
view,
|
|
24
|
+
togglePreviewStatus,
|
|
25
|
+
showPreview,
|
|
26
|
+
disabled,
|
|
27
|
+
readonly,
|
|
28
|
+
translate
|
|
29
|
+
}) => {
|
|
30
|
+
const commandRef = React.useRef<MarkdownCommand | null>(null);
|
|
31
|
+
|
|
32
|
+
React.useEffect(() => {
|
|
33
|
+
if (view) {
|
|
34
|
+
commandRef.current = new MarkdownCommand(view);
|
|
35
|
+
}
|
|
36
|
+
}, [view]);
|
|
37
|
+
|
|
38
|
+
const getTranslation = (fallback: string) : string => {
|
|
39
|
+
const key = fallback.toLowerCase().replace(" ", "-");
|
|
40
|
+
return translate(key) || fallback;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const { basic, lists, attachments } = MarkdownCommand.commands;
|
|
44
|
+
return (
|
|
45
|
+
<Toolbar noWrap>
|
|
46
|
+
<ToolbarSection canShrink hideOverflow>
|
|
47
|
+
<ContextMenu
|
|
48
|
+
togglerElement={
|
|
49
|
+
<Button
|
|
50
|
+
rightIcon={<Icon name="toggler-showmore" />}
|
|
51
|
+
text={getTranslation("Paragraphs")}
|
|
52
|
+
minimal
|
|
53
|
+
fill
|
|
54
|
+
ellipsizeText
|
|
55
|
+
disabled={showPreview || disabled || readonly}
|
|
56
|
+
/>
|
|
57
|
+
}
|
|
58
|
+
>
|
|
59
|
+
{MarkdownCommand.commands.paragraphs.map((p, i) => (
|
|
60
|
+
<MenuItem
|
|
61
|
+
key={p}
|
|
62
|
+
text={
|
|
63
|
+
<>
|
|
64
|
+
<span style={p.startsWith("Head") ? { fontSize: 22 - (i * (22 - 12)) / 5 } : {}}>
|
|
65
|
+
{getTranslation(p)}
|
|
66
|
+
</span>
|
|
67
|
+
</>
|
|
68
|
+
}
|
|
69
|
+
onClick={() => commandRef.current?.executeCommand(p)}
|
|
70
|
+
/>
|
|
71
|
+
))}
|
|
72
|
+
</ContextMenu>
|
|
73
|
+
</ToolbarSection>
|
|
74
|
+
<ToolbarSection canShrink>
|
|
75
|
+
<Spacing vertical hasDivider size="tiny" />
|
|
76
|
+
</ToolbarSection>
|
|
77
|
+
|
|
78
|
+
{[basic, lists, attachments].map((section, i) => {
|
|
79
|
+
return (
|
|
80
|
+
<React.Fragment key={i}>
|
|
81
|
+
<ToolbarSection>
|
|
82
|
+
{section.map((command) => {
|
|
83
|
+
return (
|
|
84
|
+
<IconButton
|
|
85
|
+
key={command.title}
|
|
86
|
+
name={command.icon}
|
|
87
|
+
onClick={() => commandRef.current?.executeCommand(command.title)}
|
|
88
|
+
text={getTranslation(command.title)}
|
|
89
|
+
disabled={showPreview || disabled || readonly}
|
|
90
|
+
/>
|
|
91
|
+
);
|
|
92
|
+
})}
|
|
93
|
+
</ToolbarSection>
|
|
94
|
+
{i < 2 && (
|
|
95
|
+
<ToolbarSection canShrink>
|
|
96
|
+
<Spacing vertical hasDivider size="tiny" />
|
|
97
|
+
</ToolbarSection>
|
|
98
|
+
)}
|
|
99
|
+
</React.Fragment>
|
|
100
|
+
);
|
|
101
|
+
})}
|
|
102
|
+
<ToolbarSection canGrow canShrink>
|
|
103
|
+
<Spacing vertical size="small" />
|
|
104
|
+
</ToolbarSection>
|
|
105
|
+
<ToolbarSection canShrink hideOverflow>
|
|
106
|
+
<Button
|
|
107
|
+
minimal
|
|
108
|
+
ellipsizeText
|
|
109
|
+
onClick={togglePreviewStatus}
|
|
110
|
+
text={showPreview ? getTranslation("Continue editing") : getTranslation("Preview")}
|
|
111
|
+
icon={showPreview ? "item-edit" : "item-viewdetails"}
|
|
112
|
+
disabled={disabled}
|
|
113
|
+
/>
|
|
114
|
+
</ToolbarSection>
|
|
115
|
+
</Toolbar>
|
|
116
|
+
);
|
|
117
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Diagnostic } from "@codemirror/lint";
|
|
2
|
+
import { Extension } from "@codemirror/state";
|
|
3
|
+
import { EditorView } from "@codemirror/view";
|
|
4
|
+
|
|
5
|
+
export type Linter = (view: EditorView) => ReadonlyArray<Diagnostic> | Promise<ReadonlyArray<Diagnostic>>;
|
|
6
|
+
|
|
7
|
+
export type ExtensionCreator<T = unknown> = (options?: T) => Extension;
|
|
@@ -15,3 +15,4 @@ $reactflow-edge-stroke-color-selected: $eccgui-color-accent !default;
|
|
|
15
15
|
$reactflow-transition-time: 0.25s !default;
|
|
16
16
|
$reactflow-transition-function: "" !default;
|
|
17
17
|
$reactflow-transition-anglestart: -90deg;
|
|
18
|
+
$reactflow-cursor-delimiter-offset: 0.9 * $eccgui-size-block-whitespace;
|