@eccenca/gui-elements 24.1.0-rc.4 → 24.1.0-rc.6
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 +35 -2
- package/dist/cjs/cmem/ActivityControl/ActivityControlWidget.js +7 -2
- package/dist/cjs/cmem/ActivityControl/ActivityControlWidget.js.map +1 -1
- package/dist/cjs/components/AutoSuggestion/AutoSuggestion.js +8 -0
- package/dist/cjs/components/AutoSuggestion/AutoSuggestion.js.map +1 -1
- package/dist/cjs/components/Icon/canonicalIconNames.js +10 -0
- package/dist/cjs/components/Icon/canonicalIconNames.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/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/extensions/codemirror/CodeMirror.js +37 -8
- package/dist/cjs/extensions/codemirror/CodeMirror.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/esm/cmem/ActivityControl/ActivityControlWidget.js +7 -2
- package/dist/esm/cmem/ActivityControl/ActivityControlWidget.js.map +1 -1
- package/dist/esm/components/AutoSuggestion/AutoSuggestion.js +8 -0
- package/dist/esm/components/AutoSuggestion/AutoSuggestion.js.map +1 -1
- package/dist/esm/components/Icon/canonicalIconNames.js +10 -0
- package/dist/esm/components/Icon/canonicalIconNames.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/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/extensions/codemirror/CodeMirror.js +38 -9
- package/dist/esm/extensions/codemirror/CodeMirror.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/types/cmem/ActivityControl/ActivityControlWidget.d.ts +1 -1
- package/dist/types/components/Icon/canonicalIconNames.d.ts +10 -0
- package/dist/types/components/OverviewItem/OverviewItem.d.ts +13 -1
- package/dist/types/components/OverviewItem/OverviewItemList.d.ts +3 -2
- package/dist/types/components/TextField/SearchField.d.ts +1 -1
- package/dist/types/components/Typography/OverflowText.d.ts +23 -2
- package/dist/types/extensions/codemirror/CodeMirror.d.ts +10 -1
- 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/package.json +21 -19
- package/src/cmem/ActivityControl/ActivityControlWidget.tsx +5 -2
- package/src/components/AutoSuggestion/AutoSuggestion.tsx +9 -0
- package/src/components/CodeAutocompleteField/CodeAutocompleteField.stories.tsx +3 -2
- package/src/components/ContextOverlay/ContextOverlay.stories.tsx +15 -4
- package/src/components/Depiction/depiction.scss +7 -0
- 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 +10 -0
- package/src/components/OverviewItem/OverviewItem.tsx +24 -1
- package/src/components/OverviewItem/OverviewItemList.tsx +3 -2
- package/src/components/OverviewItem/stories/OverviewItem.stories.tsx +6 -12
- package/src/components/Select/Select.stories.tsx +4 -1
- package/src/components/TextField/SearchField.tsx +37 -9
- package/src/components/TextField/stories/SearchField.stories.tsx +15 -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/extensions/codemirror/CodeMirror.stories.tsx +5 -17
- package/src/extensions/codemirror/CodeMirror.tsx +67 -8
- package/src/extensions/codemirror/_codemirror.scss +35 -2
- package/src/extensions/codemirror/toolbars/commands/markdown.command.ts +340 -0
- package/src/extensions/codemirror/toolbars/markdown.toolbar.tsx +117 -0
|
@@ -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
|
+
};
|