@eccenca/gui-elements 25.1.0-rc.0 → 25.1.0-rc.2
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 +43 -5
- package/dist/cjs/cmem/ActivityControl/ActivityControlWidget.js +17 -13
- package/dist/cjs/cmem/ActivityControl/ActivityControlWidget.js.map +1 -1
- package/dist/cjs/cmem/react-flow/StickyNoteModal/StickyNoteModal.js +1 -1
- package/dist/cjs/cmem/react-flow/StickyNoteModal/StickyNoteModal.js.map +1 -1
- package/dist/cjs/common/index.js +1 -0
- package/dist/cjs/common/index.js.map +1 -1
- package/dist/cjs/common/utils/CssCustomProperties.js.map +1 -1
- package/dist/cjs/common/utils/colorHash.js +26 -12
- package/dist/cjs/common/utils/colorHash.js.map +1 -1
- package/dist/cjs/components/ColorField/ColorField.js +114 -0
- package/dist/cjs/components/ColorField/ColorField.js.map +1 -0
- package/dist/cjs/components/ContextOverlay/ContextOverlay.js +6 -6
- package/dist/cjs/components/ContextOverlay/ContextOverlay.js.map +1 -1
- package/dist/cjs/components/DecoupledOverlay/DecoupledOverlay.js +47 -0
- package/dist/cjs/components/DecoupledOverlay/DecoupledOverlay.js.map +1 -0
- package/dist/cjs/components/Icon/canonicalIconNames.js +3 -0
- package/dist/cjs/components/Icon/canonicalIconNames.js.map +1 -1
- package/dist/cjs/components/Icon/transformIcon.js +14 -0
- package/dist/cjs/components/Icon/transformIcon.js.map +1 -0
- package/dist/cjs/components/MultiSelect/MultiSelect.js +2 -1
- package/dist/cjs/components/MultiSelect/MultiSelect.js.map +1 -1
- package/dist/cjs/components/RadioButton/RadioButton.js +5 -2
- package/dist/cjs/components/RadioButton/RadioButton.js.map +1 -1
- package/dist/cjs/components/TextField/useTextValidation.js +17 -8
- package/dist/cjs/components/TextField/useTextValidation.js.map +1 -1
- package/dist/cjs/components/VisualTour/VisualTour.js +24 -32
- package/dist/cjs/components/VisualTour/VisualTour.js.map +1 -1
- package/dist/cjs/components/index.js +2 -0
- package/dist/cjs/components/index.js.map +1 -1
- package/dist/cjs/extensions/codemirror/CodeMirror.js +56 -18
- package/dist/cjs/extensions/codemirror/CodeMirror.js.map +1 -1
- package/dist/cjs/extensions/codemirror/toolbars/EditorAppearanceConfigMenu.js +23 -0
- package/dist/cjs/extensions/codemirror/toolbars/EditorAppearanceConfigMenu.js.map +1 -0
- package/dist/cjs/extensions/codemirror/toolbars/markdown.toolbar.js +5 -2
- package/dist/cjs/extensions/codemirror/toolbars/markdown.toolbar.js.map +1 -1
- package/dist/cjs/extensions/react-flow/edges/EdgeLabel.js +1 -1
- package/dist/cjs/extensions/react-flow/edges/EdgeLabel.js.map +1 -1
- package/dist/esm/cmem/ActivityControl/ActivityControlWidget.js +19 -14
- package/dist/esm/cmem/ActivityControl/ActivityControlWidget.js.map +1 -1
- package/dist/esm/cmem/react-flow/StickyNoteModal/StickyNoteModal.js +1 -1
- package/dist/esm/cmem/react-flow/StickyNoteModal/StickyNoteModal.js.map +1 -1
- package/dist/esm/common/index.js +2 -1
- package/dist/esm/common/index.js.map +1 -1
- package/dist/esm/common/utils/CssCustomProperties.js.map +1 -1
- package/dist/esm/common/utils/colorHash.js +26 -13
- package/dist/esm/common/utils/colorHash.js.map +1 -1
- package/dist/esm/components/ColorField/ColorField.js +140 -0
- package/dist/esm/components/ColorField/ColorField.js.map +1 -0
- package/dist/esm/components/ContextOverlay/ContextOverlay.js +3 -3
- package/dist/esm/components/ContextOverlay/ContextOverlay.js.map +1 -1
- package/dist/esm/components/DecoupledOverlay/DecoupledOverlay.js +41 -0
- package/dist/esm/components/DecoupledOverlay/DecoupledOverlay.js.map +1 -0
- package/dist/esm/components/Icon/canonicalIconNames.js +3 -0
- package/dist/esm/components/Icon/canonicalIconNames.js.map +1 -1
- package/dist/esm/components/Icon/transformIcon.js +21 -0
- package/dist/esm/components/Icon/transformIcon.js.map +1 -0
- package/dist/esm/components/MultiSelect/MultiSelect.js +3 -2
- package/dist/esm/components/MultiSelect/MultiSelect.js.map +1 -1
- package/dist/esm/components/RadioButton/RadioButton.js +6 -2
- package/dist/esm/components/RadioButton/RadioButton.js.map +1 -1
- package/dist/esm/components/TextField/useTextValidation.js +39 -8
- package/dist/esm/components/TextField/useTextValidation.js.map +1 -1
- package/dist/esm/components/VisualTour/VisualTour.js +25 -33
- package/dist/esm/components/VisualTour/VisualTour.js.map +1 -1
- package/dist/esm/components/index.js +2 -0
- package/dist/esm/components/index.js.map +1 -1
- package/dist/esm/extensions/codemirror/CodeMirror.js +58 -20
- package/dist/esm/extensions/codemirror/CodeMirror.js.map +1 -1
- package/dist/esm/extensions/codemirror/toolbars/EditorAppearanceConfigMenu.js +47 -0
- package/dist/esm/extensions/codemirror/toolbars/EditorAppearanceConfigMenu.js.map +1 -0
- package/dist/esm/extensions/codemirror/toolbars/markdown.toolbar.js +16 -2
- package/dist/esm/extensions/codemirror/toolbars/markdown.toolbar.js.map +1 -1
- package/dist/esm/extensions/react-flow/edges/EdgeLabel.js +1 -1
- package/dist/esm/extensions/react-flow/edges/EdgeLabel.js.map +1 -1
- package/dist/types/cmem/ActivityControl/ActivityControlWidget.d.ts +9 -0
- package/dist/types/common/index.d.ts +2 -1
- package/dist/types/common/utils/CssCustomProperties.d.ts +2 -2
- package/dist/types/common/utils/colorHash.d.ts +5 -4
- package/dist/types/components/ColorField/ColorField.d.ts +30 -0
- package/dist/types/components/ContextOverlay/ContextOverlay.d.ts +7 -1
- package/dist/types/components/DecoupledOverlay/DecoupledOverlay.d.ts +20 -0
- package/dist/types/components/Icon/canonicalIconNames.d.ts +2 -0
- package/dist/types/components/Icon/transformIcon.d.ts +2 -0
- package/dist/types/components/MultiSelect/MultiSelect.d.ts +1 -1
- package/dist/types/components/RadioButton/RadioButton.d.ts +8 -2
- package/dist/types/components/index.d.ts +2 -0
- package/dist/types/extensions/codemirror/CodeMirror.d.ts +12 -9
- package/dist/types/extensions/codemirror/toolbars/EditorAppearanceConfigMenu.d.ts +24 -0
- package/dist/types/extensions/codemirror/toolbars/markdown.toolbar.d.ts +2 -0
- package/package.json +1 -1
- package/src/cmem/ActivityControl/ActivityControlWidget.tsx +68 -35
- package/src/cmem/react-flow/StickyNoteModal/StickyNoteModal.tsx +1 -1
- package/src/common/index.ts +2 -1
- package/src/common/utils/CssCustomProperties.ts +5 -3
- package/src/common/utils/colorHash.ts +38 -20
- package/src/components/Application/_colors.scss +15 -0
- package/src/components/ColorField/ColorField.stories.tsx +72 -0
- package/src/components/ColorField/ColorField.test.tsx +101 -0
- package/src/components/ColorField/ColorField.tsx +200 -0
- package/src/components/ColorField/_colorfield.scss +67 -0
- package/src/components/ContextOverlay/ContextOverlay.tsx +20 -1
- package/src/components/DecoupledOverlay/DecoupledOverlay.stories.tsx +30 -0
- package/src/components/DecoupledOverlay/DecoupledOverlay.tsx +97 -0
- package/src/components/DecoupledOverlay/_decoupledoverlay.scss +46 -0
- package/src/components/Icon/canonicalIconNames.tsx +3 -0
- package/src/components/Icon/transformIcon.tsx +17 -0
- package/src/components/Link/Link.stories.tsx +30 -0
- package/src/components/Link/link.scss +28 -2
- package/src/components/MultiSelect/MultiSelect.tsx +12 -3
- package/src/components/RadioButton/RadioButton.tsx +15 -3
- package/src/components/RadioButton/radiobutton.scss +13 -0
- package/src/components/TextField/stories/TextField.stories.tsx +23 -0
- package/src/components/TextField/tests/useTextValidation.test.tsx +83 -0
- package/src/components/TextField/useTextValidation.ts +17 -8
- package/src/components/VisualTour/VisualTour.tsx +30 -50
- package/src/components/VisualTour/visualTour.scss +0 -34
- package/src/components/index.scss +2 -0
- package/src/components/index.ts +2 -0
- package/src/configuration/_customproperties.scss +32 -0
- package/src/configuration/stories/customproperties.stories.tsx +118 -0
- package/src/extensions/codemirror/CodeMirror.stories.tsx +9 -4
- package/src/extensions/codemirror/CodeMirror.tsx +87 -31
- package/src/extensions/codemirror/tests/CodeEditor.test.tsx +138 -0
- package/src/extensions/codemirror/tests/EditorAppearanceConfigMenu.test.tsx +131 -0
- package/src/extensions/codemirror/toolbars/EditorAppearanceConfigMenu.tsx +59 -0
- package/src/extensions/codemirror/toolbars/markdown.toolbar.tsx +17 -3
- package/src/extensions/react-flow/_config.scss +3 -3
- package/src/extensions/react-flow/edges/EdgeLabel.tsx +5 -3
- package/src/extensions/react-flow/edges/_edges.scss +3 -2
- package/src/index.scss +1 -0
|
@@ -6,6 +6,7 @@ import { DOMEventHandlers, EditorView, KeyBinding, keymap, Rect, ViewUpdate } fr
|
|
|
6
6
|
import { minimalSetup } from "codemirror";
|
|
7
7
|
|
|
8
8
|
import { Markdown } from "../../cmem/markdown/Markdown";
|
|
9
|
+
import { EditorAppearanceConfigMenu } from "./toolbars/EditorAppearanceConfigMenu";
|
|
9
10
|
import { IntentTypes } from "../../common/Intent";
|
|
10
11
|
import { markField } from "../../components/AutoSuggestion/extensions/markText";
|
|
11
12
|
import { TestableComponent } from "../../components/interfaces";
|
|
@@ -36,7 +37,17 @@ import {
|
|
|
36
37
|
import { MarkdownToolbar } from "./toolbars/markdown.toolbar";
|
|
37
38
|
import { ExtensionCreator } from "./types";
|
|
38
39
|
|
|
39
|
-
|
|
40
|
+
interface EditorAppearance {
|
|
41
|
+
/**
|
|
42
|
+
* If enabled the code editor won't show numbers before each line.
|
|
43
|
+
*/
|
|
44
|
+
preventLineNumbers?: boolean;
|
|
45
|
+
|
|
46
|
+
/** Long lines are wrapped and displayed on multiple lines */
|
|
47
|
+
wrapLines?: boolean;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface CodeEditorProps extends EditorAppearance, Omit<React.HTMLAttributes<HTMLDivElement>, "translate" | "onChange" | "onKeyDown" | "onMouseDown" | "onScroll">, TestableComponent {
|
|
40
51
|
// Is called with the editor instance that allows access via the CodeMirror API
|
|
41
52
|
setEditorView?: (editor: EditorView | undefined) => void;
|
|
42
53
|
/**
|
|
@@ -86,10 +97,6 @@ export interface CodeEditorProps extends Omit<React.HTMLAttributes<HTMLDivElemen
|
|
|
86
97
|
* Default value used first when the editor is instanciated.
|
|
87
98
|
*/
|
|
88
99
|
defaultValue?: string;
|
|
89
|
-
/**
|
|
90
|
-
* If enabled the code editor won't show numbers before each line.
|
|
91
|
-
*/
|
|
92
|
-
preventLineNumbers?: boolean;
|
|
93
100
|
|
|
94
101
|
/** Set read-only mode. Default: false */
|
|
95
102
|
readOnly?: boolean;
|
|
@@ -97,11 +104,8 @@ export interface CodeEditorProps extends Omit<React.HTMLAttributes<HTMLDivElemen
|
|
|
97
104
|
/** Optional height of the component */
|
|
98
105
|
height?: number | string;
|
|
99
106
|
|
|
100
|
-
/** Long lines are wrapped and displayed on multiple lines */
|
|
101
|
-
wrapLines?: boolean;
|
|
102
|
-
|
|
103
107
|
/**
|
|
104
|
-
* Add properties to the `div` used as
|
|
108
|
+
* Add properties to the `div` used as wrapper element.
|
|
105
109
|
* @deprecated (v26) You can now use all properties directly on `CodeEditor`.
|
|
106
110
|
*/
|
|
107
111
|
outerDivAttributes?: Omit<React.HTMLAttributes<HTMLDivElement>, "id" | "data-test-id" | "data-testid" | "translate" | "onChange" | "onKeyDown" | "onMouseDown" | "onScroll">;
|
|
@@ -186,6 +190,18 @@ const ModeLinterMap: ReadonlyMap<SupportedCodeEditorModes, ReadonlyArray<Extensi
|
|
|
186
190
|
|
|
187
191
|
const ModeToolbarSupport: ReadonlyArray<SupportedCodeEditorModes> = ["markdown"];
|
|
188
192
|
|
|
193
|
+
const defaultAppearanceForModeWithToolbar: ReadonlyMap<SupportedCodeEditorModes, EditorAppearance> = new Map([
|
|
194
|
+
["markdown", { wrapLines: true, preventLineNumbers: true }]
|
|
195
|
+
]);
|
|
196
|
+
|
|
197
|
+
const getDefaultAppearanceForModeWithToolbar = (hasToolbar: boolean, mode?: SupportedCodeEditorModes): EditorAppearance | undefined => {
|
|
198
|
+
if (hasToolbar && mode) {
|
|
199
|
+
return defaultAppearanceForModeWithToolbar.get(mode);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
return undefined;
|
|
203
|
+
}
|
|
204
|
+
|
|
189
205
|
/**
|
|
190
206
|
* Includes a code editor, currently we use CodeMirror library as base.
|
|
191
207
|
*/
|
|
@@ -200,11 +216,11 @@ export const CodeEditor = ({
|
|
|
200
216
|
name,
|
|
201
217
|
id,
|
|
202
218
|
mode,
|
|
203
|
-
preventLineNumbers
|
|
219
|
+
preventLineNumbers,
|
|
220
|
+
wrapLines,
|
|
204
221
|
defaultValue = "",
|
|
205
222
|
readOnly = false,
|
|
206
223
|
shouldHaveMinimalSetup = true,
|
|
207
|
-
wrapLines = false,
|
|
208
224
|
onScroll,
|
|
209
225
|
setEditorView,
|
|
210
226
|
supportCodeFolding = false,
|
|
@@ -221,16 +237,30 @@ export const CodeEditor = ({
|
|
|
221
237
|
autoFocus = false,
|
|
222
238
|
disabled = false,
|
|
223
239
|
intent,
|
|
224
|
-
useToolbar,
|
|
240
|
+
useToolbar = false,
|
|
225
241
|
translate,
|
|
226
242
|
...otherCodeEditorProps
|
|
227
243
|
}: CodeEditorProps) => {
|
|
228
244
|
const parent = useRef<any>(undefined);
|
|
229
245
|
const [view, setView] = React.useState<EditorView | undefined>();
|
|
246
|
+
const defaultAppearanceForModeWithToolbar = getDefaultAppearanceForModeWithToolbar(useToolbar, mode);
|
|
247
|
+
const [editorAppearance, setEditorAppearance] = React.useState<{[s: string]: boolean;}>(
|
|
248
|
+
{
|
|
249
|
+
// we also set the fallback default here
|
|
250
|
+
wrapLines: wrapLines ?? defaultAppearanceForModeWithToolbar?.wrapLines ?? false,
|
|
251
|
+
preventLineNumbers: preventLineNumbers ?? defaultAppearanceForModeWithToolbar?.preventLineNumbers ?? false,
|
|
252
|
+
}
|
|
253
|
+
)
|
|
230
254
|
const currentView = React.useRef<EditorView>()
|
|
231
255
|
currentView.current = view
|
|
232
256
|
const currentReadOnly = React.useRef(readOnly)
|
|
233
257
|
currentReadOnly.current = readOnly
|
|
258
|
+
const currentOnChange = React.useRef(onChange)
|
|
259
|
+
currentOnChange.current = onChange
|
|
260
|
+
const currentDisabled = React.useRef(disabled)
|
|
261
|
+
currentDisabled.current = disabled
|
|
262
|
+
const currentIntent = React.useRef(intent)
|
|
263
|
+
currentIntent.current = intent
|
|
234
264
|
const [showPreview, setShowPreview] = React.useState<boolean>(false);
|
|
235
265
|
// CodeMirror Compartments in order to allow for re-configuration after initialization
|
|
236
266
|
const readOnlyCompartment = React.useRef<Compartment>(compartment())
|
|
@@ -319,18 +349,18 @@ export const CodeEditor = ({
|
|
|
319
349
|
disabledCompartment.current.of(EditorView?.editable.of(!disabled)),
|
|
320
350
|
AdaptedEditorViewDomEventHandlers(domEventHandlers) as Extension,
|
|
321
351
|
EditorView?.updateListener.of((v: ViewUpdate) => {
|
|
322
|
-
if (
|
|
352
|
+
if (currentDisabled.current) return;
|
|
323
353
|
|
|
324
|
-
if (
|
|
354
|
+
if (currentOnChange.current && v.docChanged) {
|
|
325
355
|
// Only fire if the text has actually been changed
|
|
326
|
-
|
|
356
|
+
currentOnChange.current(v.state.doc.toString());
|
|
327
357
|
}
|
|
328
358
|
|
|
329
359
|
if (onSelection)
|
|
330
360
|
onSelection(v.state.selection.ranges.filter((r) => !r.empty).map(({ from, to }) => ({ from, to })));
|
|
331
361
|
|
|
332
|
-
if (onFocusChange &&
|
|
333
|
-
v.view.dom.classList.add(`${eccgui}-intent--${
|
|
362
|
+
if (onFocusChange && currentIntent.current && !v.view.dom.classList?.contains(`${eccgui}-intent--${currentIntent.current}`)) {
|
|
363
|
+
v.view.dom.classList.add(`${eccgui}-intent--${currentIntent.current}`);
|
|
334
364
|
}
|
|
335
365
|
|
|
336
366
|
if (onCursorChange) {
|
|
@@ -353,9 +383,9 @@ export const CodeEditor = ({
|
|
|
353
383
|
}
|
|
354
384
|
}),
|
|
355
385
|
shouldHaveMinimalSetupCompartment.current.of(addExtensionsFor(shouldHaveMinimalSetup, minimalSetup)),
|
|
356
|
-
preventLineNumbersCompartment.current.of(addExtensionsFor(!preventLineNumbers, adaptedLineNumbers())),
|
|
386
|
+
preventLineNumbersCompartment.current.of(addExtensionsFor(!editorAppearance.preventLineNumbers, adaptedLineNumbers())),
|
|
357
387
|
shouldHighlightActiveLineCompartment.current.of(addExtensionsFor(shouldHighlightActiveLine, adaptedHighlightActiveLine())),
|
|
358
|
-
wrapLinesCompartment.current.of(addExtensionsFor(wrapLines, EditorView?.lineWrapping)),
|
|
388
|
+
wrapLinesCompartment.current.of(addExtensionsFor((editorAppearance.wrapLines!), EditorView?.lineWrapping)),
|
|
359
389
|
supportCodeFoldingCompartment.current.of(addExtensionsFor(supportCodeFolding, adaptedFoldGutter(), adaptedCodeFolding())),
|
|
360
390
|
useLintingCompartment.current.of(addExtensionsFor(useLinting, ...linters)),
|
|
361
391
|
adaptedSyntaxHighlighting(defaultHighlightStyle),
|
|
@@ -377,11 +407,11 @@ export const CodeEditor = ({
|
|
|
377
407
|
}
|
|
378
408
|
|
|
379
409
|
if (disabled) {
|
|
380
|
-
view.dom.
|
|
410
|
+
view.dom.classList.add(`${eccgui}-disabled`);
|
|
381
411
|
}
|
|
382
412
|
|
|
383
|
-
if (
|
|
384
|
-
view.dom.className += ` ${eccgui}-intent--${
|
|
413
|
+
if (currentIntent.current) {
|
|
414
|
+
view.dom.className += ` ${eccgui}-intent--${currentIntent.current}`;
|
|
385
415
|
}
|
|
386
416
|
|
|
387
417
|
if (autoFocus) {
|
|
@@ -432,24 +462,39 @@ export const CodeEditor = ({
|
|
|
432
462
|
}, [tabIntentSize])
|
|
433
463
|
|
|
434
464
|
React.useEffect(() => {
|
|
435
|
-
updateExtension(EditorView?.editable.of(!disabled), disabledCompartment.current)
|
|
465
|
+
updateExtension(EditorView?.editable.of(!disabled), disabledCompartment.current);
|
|
466
|
+
if (view?.dom) {
|
|
467
|
+
if (disabled) {
|
|
468
|
+
view.dom.classList.add(`${eccgui}-disabled`);
|
|
469
|
+
} else {
|
|
470
|
+
view.dom.classList.remove(`${eccgui}-disabled`);
|
|
471
|
+
}
|
|
472
|
+
}
|
|
436
473
|
}, [disabled])
|
|
437
474
|
|
|
438
475
|
React.useEffect(() => {
|
|
439
|
-
|
|
440
|
-
|
|
476
|
+
setEditorAppearance({
|
|
477
|
+
...editorAppearance,
|
|
478
|
+
preventLineNumbers: preventLineNumbers ?? editorAppearance?.preventLineNumbers ?? false,
|
|
479
|
+
});
|
|
480
|
+
updateExtension(addExtensionsFor(!editorAppearance.preventLineNumbers, adaptedLineNumbers()), preventLineNumbersCompartment.current)
|
|
481
|
+
}, [preventLineNumbers, editorAppearance.preventLineNumbers])
|
|
441
482
|
|
|
442
483
|
React.useEffect(() => {
|
|
443
|
-
|
|
444
|
-
|
|
484
|
+
setEditorAppearance({
|
|
485
|
+
...editorAppearance,
|
|
486
|
+
wrapLines: wrapLines ?? editorAppearance?.wrapLines ?? false,
|
|
487
|
+
});
|
|
488
|
+
updateExtension(addExtensionsFor(editorAppearance.wrapLines!, EditorView?.lineWrapping), wrapLinesCompartment.current)
|
|
489
|
+
}, [wrapLines, editorAppearance.wrapLines])
|
|
445
490
|
|
|
446
491
|
React.useEffect(() => {
|
|
447
|
-
updateExtension(addExtensionsFor(
|
|
448
|
-
}, [
|
|
492
|
+
updateExtension(addExtensionsFor(shouldHaveMinimalSetup ?? true, minimalSetup), shouldHaveMinimalSetupCompartment.current)
|
|
493
|
+
}, [shouldHaveMinimalSetup])
|
|
449
494
|
|
|
450
495
|
React.useEffect(() => {
|
|
451
|
-
updateExtension(addExtensionsFor(
|
|
452
|
-
}, [
|
|
496
|
+
updateExtension(addExtensionsFor(shouldHighlightActiveLine ?? false, adaptedHighlightActiveLine()), shouldHighlightActiveLineCompartment.current)
|
|
497
|
+
}, [shouldHighlightActiveLine])
|
|
453
498
|
|
|
454
499
|
React.useEffect(() => {
|
|
455
500
|
updateExtension(addExtensionsFor(supportCodeFolding ?? false, adaptedFoldGutter(), adaptedCodeFolding()), supportCodeFoldingCompartment.current)
|
|
@@ -474,6 +519,17 @@ export const CodeEditor = ({
|
|
|
474
519
|
translate={getTranslation}
|
|
475
520
|
disabled={disabled}
|
|
476
521
|
readonly={readOnly}
|
|
522
|
+
configMenu={(
|
|
523
|
+
<EditorAppearanceConfigMenu
|
|
524
|
+
config={{...editorAppearance}}
|
|
525
|
+
configLocked={{
|
|
526
|
+
wrapLines,
|
|
527
|
+
preventLineNumbers,
|
|
528
|
+
}}
|
|
529
|
+
setConfig={setEditorAppearance}
|
|
530
|
+
configPropertyTranslate={getTranslation}
|
|
531
|
+
/>
|
|
532
|
+
)}
|
|
477
533
|
/>
|
|
478
534
|
</div>
|
|
479
535
|
{showPreview && (
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { fireEvent, render, screen } from "@testing-library/react";
|
|
3
|
+
|
|
4
|
+
import "@testing-library/jest-dom";
|
|
5
|
+
|
|
6
|
+
import { CLASSPREFIX as eccgui } from "../../../configuration/constants";
|
|
7
|
+
import { CodeEditor } from "../CodeMirror";
|
|
8
|
+
|
|
9
|
+
const contextOverlayClass = `${eccgui}-contextoverlay`;
|
|
10
|
+
|
|
11
|
+
const setupDocumentRange = () => {
|
|
12
|
+
document.createRange = () => {
|
|
13
|
+
const range = new Range();
|
|
14
|
+
range.getBoundingClientRect = jest.fn();
|
|
15
|
+
range.getClientRects = () => ({
|
|
16
|
+
item: () => null,
|
|
17
|
+
length: 0,
|
|
18
|
+
[Symbol.iterator]: jest.fn(),
|
|
19
|
+
});
|
|
20
|
+
return range;
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
describe("CodeEditor - markdown mode with toolbar", () => {
|
|
25
|
+
beforeAll(() => {
|
|
26
|
+
setupDocumentRange();
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
// The toolbar contains a Paragraphs ContextMenu first, then the EditorAppearanceConfigMenu last.
|
|
30
|
+
const getConfigMenuOverlay = (container: HTMLElement) => {
|
|
31
|
+
const overlays = container.getElementsByClassName(contextOverlayClass);
|
|
32
|
+
return overlays[overlays.length - 1] as HTMLElement;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
it("renders toolbar when mode is markdown and useToolbar is true", () => {
|
|
36
|
+
const { container } = render(<CodeEditor name="test-editor" mode="markdown" useToolbar={true} />);
|
|
37
|
+
expect(container.querySelector(`.${eccgui}-codeeditor__toolbar`)).not.toBeNull();
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it("does not render toolbar when useToolbar is false", () => {
|
|
41
|
+
const { container } = render(<CodeEditor name="test-editor" mode="markdown" useToolbar={false} />);
|
|
42
|
+
expect(container.querySelector(`.${eccgui}-codeeditor__toolbar`)).toBeNull();
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it("does not render toolbar for non-markdown modes even when useToolbar is true", () => {
|
|
46
|
+
const { container } = render(<CodeEditor name="test-editor" mode="yaml" useToolbar={true} />);
|
|
47
|
+
expect(container.querySelector(`.${eccgui}-codeeditor__toolbar`)).toBeNull();
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it("includes the EditorAppearanceConfigMenu in the markdown toolbar", () => {
|
|
51
|
+
const { container } = render(<CodeEditor name="test-editor" mode="markdown" useToolbar={true} />);
|
|
52
|
+
const toolbar = container.querySelector(`.${eccgui}-codeeditor__toolbar`);
|
|
53
|
+
// Toolbar contains at least the Paragraphs menu and the EditorAppearanceConfigMenu
|
|
54
|
+
expect(toolbar?.getElementsByClassName(contextOverlayClass).length).toBeGreaterThanOrEqual(2);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it("defaults wrapLines to true in markdown mode with toolbar", async () => {
|
|
58
|
+
const { container } = render(<CodeEditor name="test-editor" mode="markdown" useToolbar={true} />);
|
|
59
|
+
|
|
60
|
+
fireEvent.click(getConfigMenuOverlay(container));
|
|
61
|
+
|
|
62
|
+
const wrapLinesItem = await screen.findByText("wrapLines");
|
|
63
|
+
expect(wrapLinesItem.closest("[aria-selected='true']")).not.toBeNull();
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it("defaults preventLineNumbers to true in markdown mode with toolbar", async () => {
|
|
67
|
+
const { container } = render(<CodeEditor name="test-editor" mode="markdown" useToolbar={true} />);
|
|
68
|
+
|
|
69
|
+
fireEvent.click(getConfigMenuOverlay(container));
|
|
70
|
+
|
|
71
|
+
const preventLineNumbersItem = await screen.findByText("preventLineNumbers");
|
|
72
|
+
expect(preventLineNumbersItem.closest("[aria-selected='true']")).not.toBeNull();
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it("locks wrapLines in config menu when wrapLines prop is explicitly provided", async () => {
|
|
76
|
+
const { container } = render(
|
|
77
|
+
<CodeEditor name="test-editor" mode="markdown" useToolbar={true} wrapLines={false} />
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
fireEvent.click(getConfigMenuOverlay(container));
|
|
81
|
+
|
|
82
|
+
const wrapLinesItem = await screen.findByText("wrapLines");
|
|
83
|
+
expect(wrapLinesItem.closest("[aria-disabled='true']")).not.toBeNull();
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it("locks preventLineNumbers in config menu when preventLineNumbers prop is explicitly provided", async () => {
|
|
87
|
+
const { container } = render(
|
|
88
|
+
<CodeEditor name="test-editor" mode="markdown" useToolbar={true} preventLineNumbers={false} />
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
fireEvent.click(getConfigMenuOverlay(container));
|
|
92
|
+
|
|
93
|
+
const preventLineNumbersItem = await screen.findByText("preventLineNumbers");
|
|
94
|
+
expect(preventLineNumbersItem.closest("[aria-disabled='true']")).not.toBeNull();
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it("does not lock wrapLines in config menu when wrapLines prop is not provided", async () => {
|
|
98
|
+
const { container } = render(<CodeEditor name="test-editor" mode="markdown" useToolbar={true} />);
|
|
99
|
+
|
|
100
|
+
fireEvent.click(getConfigMenuOverlay(container));
|
|
101
|
+
|
|
102
|
+
const wrapLinesItem = await screen.findByText("wrapLines");
|
|
103
|
+
expect(wrapLinesItem.closest("[aria-disabled='true']")).toBeNull();
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it("does not lock preventLineNumbers in config menu when preventLineNumbers prop is not provided", async () => {
|
|
107
|
+
const { container } = render(<CodeEditor name="test-editor" mode="markdown" useToolbar={true} />);
|
|
108
|
+
|
|
109
|
+
fireEvent.click(getConfigMenuOverlay(container));
|
|
110
|
+
|
|
111
|
+
const preventLineNumbersItem = await screen.findByText("preventLineNumbers");
|
|
112
|
+
expect(preventLineNumbersItem.closest("[aria-disabled='true']")).toBeNull();
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it("disables config menu trigger when both wrapLines and preventLineNumbers props are provided", () => {
|
|
116
|
+
const { container } = render(
|
|
117
|
+
<CodeEditor
|
|
118
|
+
name="test-editor"
|
|
119
|
+
mode="markdown"
|
|
120
|
+
useToolbar={true}
|
|
121
|
+
wrapLines={true}
|
|
122
|
+
preventLineNumbers={true}
|
|
123
|
+
/>
|
|
124
|
+
);
|
|
125
|
+
|
|
126
|
+
const configMenuTrigger = getConfigMenuOverlay(container).querySelector("button");
|
|
127
|
+
expect(configMenuTrigger).toBeDisabled();
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it("disables config menu trigger when editor is disabled", () => {
|
|
131
|
+
const { container } = render(
|
|
132
|
+
<CodeEditor name="test-editor" mode="markdown" useToolbar={true} disabled={true} />
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
const configMenuTrigger = getConfigMenuOverlay(container).querySelector("button");
|
|
136
|
+
expect(configMenuTrigger).toBeDisabled();
|
|
137
|
+
});
|
|
138
|
+
});
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { fireEvent, render, screen } from "@testing-library/react";
|
|
3
|
+
|
|
4
|
+
import "@testing-library/jest-dom";
|
|
5
|
+
|
|
6
|
+
import { CLASSPREFIX as eccgui } from "../../../configuration/constants";
|
|
7
|
+
import { EditorAppearanceConfigMenu } from "../toolbars/EditorAppearanceConfigMenu";
|
|
8
|
+
|
|
9
|
+
const contextOverlayClass = `${eccgui}-contextoverlay`;
|
|
10
|
+
|
|
11
|
+
describe("EditorAppearanceConfigMenu", () => {
|
|
12
|
+
it("renders menu items for each config property, using key as fallback label", async () => {
|
|
13
|
+
const config = { wrapLines: true, preventLineNumbers: false };
|
|
14
|
+
const setConfig = jest.fn();
|
|
15
|
+
|
|
16
|
+
const { container } = render(<EditorAppearanceConfigMenu config={config} setConfig={setConfig} />);
|
|
17
|
+
|
|
18
|
+
fireEvent.click(container.getElementsByClassName(contextOverlayClass)[0]);
|
|
19
|
+
|
|
20
|
+
expect(await screen.findByText("wrapLines")).toBeVisible();
|
|
21
|
+
expect(await screen.findByText("preventLineNumbers")).toBeVisible();
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it("uses configPropertyTranslate for menu item labels", async () => {
|
|
25
|
+
const config = { wrapLines: true, preventLineNumbers: false };
|
|
26
|
+
const setConfig = jest.fn();
|
|
27
|
+
const translate = (key: string) => `Label_${key}` as string | false;
|
|
28
|
+
|
|
29
|
+
const { container } = render(
|
|
30
|
+
<EditorAppearanceConfigMenu config={config} setConfig={setConfig} configPropertyTranslate={translate} />
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
fireEvent.click(container.getElementsByClassName(contextOverlayClass)[0]);
|
|
34
|
+
|
|
35
|
+
expect(await screen.findByText("Label_wrapLines")).toBeVisible();
|
|
36
|
+
expect(await screen.findByText("Label_preventLineNumbers")).toBeVisible();
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it("calls setConfig with the toggled value when a menu item is clicked", async () => {
|
|
40
|
+
const config = { wrapLines: true, preventLineNumbers: false };
|
|
41
|
+
const setConfig = jest.fn();
|
|
42
|
+
|
|
43
|
+
const { container } = render(<EditorAppearanceConfigMenu config={config} setConfig={setConfig} />);
|
|
44
|
+
|
|
45
|
+
fireEvent.click(container.getElementsByClassName(contextOverlayClass)[0]);
|
|
46
|
+
const wrapLinesItem = await screen.findByText("wrapLines");
|
|
47
|
+
fireEvent.click(wrapLinesItem);
|
|
48
|
+
|
|
49
|
+
expect(setConfig).toHaveBeenCalledWith({ wrapLines: false, preventLineNumbers: false });
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it("menu trigger is disabled when all config properties are locked", () => {
|
|
53
|
+
const config = { wrapLines: true, preventLineNumbers: false };
|
|
54
|
+
const configLocked = { wrapLines: true, preventLineNumbers: true };
|
|
55
|
+
const setConfig = jest.fn();
|
|
56
|
+
|
|
57
|
+
const { container } = render(
|
|
58
|
+
<EditorAppearanceConfigMenu config={config} configLocked={configLocked} setConfig={setConfig} />
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
const trigger = container.getElementsByClassName(contextOverlayClass)[0].querySelector("button");
|
|
62
|
+
expect(trigger).toBeDisabled();
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it("menu trigger is enabled when not all config properties are locked", () => {
|
|
66
|
+
const config = { wrapLines: true, preventLineNumbers: false };
|
|
67
|
+
const configLocked = { wrapLines: true }; // only one locked
|
|
68
|
+
const setConfig = jest.fn();
|
|
69
|
+
|
|
70
|
+
const { container } = render(
|
|
71
|
+
<EditorAppearanceConfigMenu config={config} configLocked={configLocked} setConfig={setConfig} />
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
const trigger = container.getElementsByClassName(contextOverlayClass)[0].querySelector("button");
|
|
75
|
+
expect(trigger).not.toBeDisabled();
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it("locked config property has a disabled menu item", async () => {
|
|
79
|
+
const config = { wrapLines: true, preventLineNumbers: false };
|
|
80
|
+
const configLocked = { wrapLines: true };
|
|
81
|
+
const setConfig = jest.fn();
|
|
82
|
+
|
|
83
|
+
const { container } = render(
|
|
84
|
+
<EditorAppearanceConfigMenu config={config} configLocked={configLocked} setConfig={setConfig} />
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
fireEvent.click(container.getElementsByClassName(contextOverlayClass)[0]);
|
|
88
|
+
|
|
89
|
+
const wrapLinesItem = await screen.findByText("wrapLines");
|
|
90
|
+
expect(wrapLinesItem.closest("[aria-disabled='true']")).not.toBeNull();
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it("unlocked config property has an enabled menu item", async () => {
|
|
94
|
+
const config = { wrapLines: true, preventLineNumbers: false };
|
|
95
|
+
const configLocked = { wrapLines: true }; // only wrapLines is locked
|
|
96
|
+
const setConfig = jest.fn();
|
|
97
|
+
|
|
98
|
+
const { container } = render(
|
|
99
|
+
<EditorAppearanceConfigMenu config={config} configLocked={configLocked} setConfig={setConfig} />
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
fireEvent.click(container.getElementsByClassName(contextOverlayClass)[0]);
|
|
103
|
+
|
|
104
|
+
const preventLineNumbersItem = await screen.findByText("preventLineNumbers");
|
|
105
|
+
expect(preventLineNumbersItem.closest("[aria-disabled='true']")).toBeNull();
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it("selected config property is marked as selected in the menu", async () => {
|
|
109
|
+
const config = { wrapLines: true, preventLineNumbers: false };
|
|
110
|
+
const setConfig = jest.fn();
|
|
111
|
+
|
|
112
|
+
const { container } = render(<EditorAppearanceConfigMenu config={config} setConfig={setConfig} />);
|
|
113
|
+
|
|
114
|
+
fireEvent.click(container.getElementsByClassName(contextOverlayClass)[0]);
|
|
115
|
+
|
|
116
|
+
const wrapLinesItem = await screen.findByText("wrapLines");
|
|
117
|
+
expect(wrapLinesItem.closest("[aria-selected='true']")).not.toBeNull();
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it("unselected config property is not marked as selected in the menu", async () => {
|
|
121
|
+
const config = { wrapLines: true, preventLineNumbers: false };
|
|
122
|
+
const setConfig = jest.fn();
|
|
123
|
+
|
|
124
|
+
const { container } = render(<EditorAppearanceConfigMenu config={config} setConfig={setConfig} />);
|
|
125
|
+
|
|
126
|
+
fireEvent.click(container.getElementsByClassName(contextOverlayClass)[0]);
|
|
127
|
+
|
|
128
|
+
const preventLineNumbersItem = await screen.findByText("preventLineNumbers");
|
|
129
|
+
expect(preventLineNumbersItem.closest("[aria-selected='true']")).toBeNull();
|
|
130
|
+
});
|
|
131
|
+
});
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
|
|
3
|
+
import { ContextMenu, ContextMenuProps, MenuItem } from "../../../components";
|
|
4
|
+
|
|
5
|
+
export interface EditorAppearanceConfigMenuProps {
|
|
6
|
+
/** Object containing a `true`/`false` value for each property */
|
|
7
|
+
config: { [s: string]: boolean };
|
|
8
|
+
/** Object containing `true` for each property that cannot be changed by user */
|
|
9
|
+
configLocked?: { [s: string]: boolean | undefined };
|
|
10
|
+
/** Handler that returns a translation for each config property key */
|
|
11
|
+
configPropertyTranslate?: (key: string) => string | false;
|
|
12
|
+
/** Handler to update config after user changes */
|
|
13
|
+
setConfig: React.Dispatch<React.SetStateAction<{ [s: string]: boolean }>>;
|
|
14
|
+
/** Additional properties used for the included `ContextMenu` */
|
|
15
|
+
contextMenuProps?: ContextMenuProps;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Returns a simple context menu that provides switches to control the editor appearance.
|
|
20
|
+
*/
|
|
21
|
+
export function EditorAppearanceConfigMenu({
|
|
22
|
+
config,
|
|
23
|
+
configLocked = {},
|
|
24
|
+
configPropertyTranslate = (s) => s,
|
|
25
|
+
setConfig,
|
|
26
|
+
contextMenuProps,
|
|
27
|
+
}: EditorAppearanceConfigMenuProps) {
|
|
28
|
+
return (
|
|
29
|
+
<ContextMenu
|
|
30
|
+
togglerElement={"item-settings"}
|
|
31
|
+
{...contextMenuProps}
|
|
32
|
+
disabled={
|
|
33
|
+
contextMenuProps?.disabled ??
|
|
34
|
+
Object.values(config).length ===
|
|
35
|
+
Object.values(configLocked).filter((value) => {
|
|
36
|
+
return typeof value !== "undefined";
|
|
37
|
+
}).length
|
|
38
|
+
}
|
|
39
|
+
>
|
|
40
|
+
{Object.entries(config).map(([key, value]) => {
|
|
41
|
+
return (
|
|
42
|
+
<MenuItem
|
|
43
|
+
key={key}
|
|
44
|
+
roleStructure={"listoption"}
|
|
45
|
+
selected={value}
|
|
46
|
+
text={configPropertyTranslate(key) || key}
|
|
47
|
+
disabled={typeof configLocked[key] !== "undefined"}
|
|
48
|
+
onClick={() => {
|
|
49
|
+
setConfig({
|
|
50
|
+
...config,
|
|
51
|
+
[key]: !value,
|
|
52
|
+
});
|
|
53
|
+
}}
|
|
54
|
+
/>
|
|
55
|
+
);
|
|
56
|
+
})}
|
|
57
|
+
</ContextMenu>
|
|
58
|
+
);
|
|
59
|
+
}
|
|
@@ -9,6 +9,7 @@ import { Spacing } from "../../../components/Separation/Spacing";
|
|
|
9
9
|
import { Toolbar, ToolbarSection } from "../../../components/Toolbar";
|
|
10
10
|
|
|
11
11
|
import MarkdownCommand from "./commands/markdown.command";
|
|
12
|
+
import { EditorAppearanceConfigMenu } from "./EditorAppearanceConfigMenu";
|
|
12
13
|
|
|
13
14
|
interface MarkdownToolbarProps {
|
|
14
15
|
view?: EditorView;
|
|
@@ -17,6 +18,7 @@ interface MarkdownToolbarProps {
|
|
|
17
18
|
translate: (key: string) => string | false;
|
|
18
19
|
disabled?: boolean;
|
|
19
20
|
readonly?: boolean;
|
|
21
|
+
configMenu?: React.ReactElement<typeof EditorAppearanceConfigMenu>;
|
|
20
22
|
}
|
|
21
23
|
|
|
22
24
|
export const MarkdownToolbar: React.FC<MarkdownToolbarProps> = ({
|
|
@@ -25,7 +27,8 @@ export const MarkdownToolbar: React.FC<MarkdownToolbarProps> = ({
|
|
|
25
27
|
showPreview,
|
|
26
28
|
disabled,
|
|
27
29
|
readonly,
|
|
28
|
-
translate
|
|
30
|
+
translate,
|
|
31
|
+
configMenu,
|
|
29
32
|
}) => {
|
|
30
33
|
const commandRef = React.useRef<MarkdownCommand | null>(null);
|
|
31
34
|
|
|
@@ -35,10 +38,10 @@ export const MarkdownToolbar: React.FC<MarkdownToolbarProps> = ({
|
|
|
35
38
|
}
|
|
36
39
|
}, [view]);
|
|
37
40
|
|
|
38
|
-
const getTranslation = (fallback: string)
|
|
41
|
+
const getTranslation = (fallback: string): string => {
|
|
39
42
|
const key = fallback.toLowerCase().replace(" ", "-");
|
|
40
43
|
return translate(key) || fallback;
|
|
41
|
-
}
|
|
44
|
+
};
|
|
42
45
|
|
|
43
46
|
const { basic, lists, attachments } = MarkdownCommand.commands;
|
|
44
47
|
return (
|
|
@@ -112,6 +115,17 @@ export const MarkdownToolbar: React.FC<MarkdownToolbarProps> = ({
|
|
|
112
115
|
disabled={disabled}
|
|
113
116
|
/>
|
|
114
117
|
</ToolbarSection>
|
|
118
|
+
{configMenu && (
|
|
119
|
+
<ToolbarSection>
|
|
120
|
+
<Spacing vertical size="small" hasDivider />
|
|
121
|
+
{React.cloneElement(configMenu, {
|
|
122
|
+
...{
|
|
123
|
+
...configMenu.props,
|
|
124
|
+
contextMenuProps: { disabled: showPreview || disabled ? true : undefined },
|
|
125
|
+
},
|
|
126
|
+
})}
|
|
127
|
+
</ToolbarSection>
|
|
128
|
+
)}
|
|
115
129
|
</Toolbar>
|
|
116
130
|
);
|
|
117
131
|
};
|
|
@@ -8,9 +8,9 @@ $reactflow-node-font-size: $eccgui-size-typo-caption !default;
|
|
|
8
8
|
$reactflow-node-border-width: 2 * $button-border-width !default;
|
|
9
9
|
$reactflow-node-border-radius: $button-border-radius !default;
|
|
10
10
|
$reactflow-edge-rendering: geometricprecision !default;
|
|
11
|
-
$reactflow-edge-stroke-width-default:
|
|
12
|
-
$reactflow-edge-stroke-width-hover:
|
|
13
|
-
$reactflow-edge-stroke-width-selected:
|
|
11
|
+
$reactflow-edge-stroke-width-default: 1px !default;
|
|
12
|
+
$reactflow-edge-stroke-width-hover: 1px !default;
|
|
13
|
+
$reactflow-edge-stroke-width-selected: 1px !default;
|
|
14
14
|
$reactflow-edge-stroke-opacity-default: $eccgui-opacity-muted !default;
|
|
15
15
|
$reactflow-edge-stroke-opacity-hover: $eccgui-opacity-narrow !default;
|
|
16
16
|
$reactflow-edge-stroke-opacity-selected: $eccgui-opacity-regular !default;
|
|
@@ -81,9 +81,11 @@ export const EdgeLabel = memo(
|
|
|
81
81
|
})}
|
|
82
82
|
</div>
|
|
83
83
|
)}
|
|
84
|
-
|
|
85
|
-
{
|
|
86
|
-
|
|
84
|
+
{(title || text) && (
|
|
85
|
+
<div className={`${eccgui}-graphviz__edge-label__text`} title={title??undefined}>
|
|
86
|
+
{text && (typeof text === "string" ? <OverflowText>{text}</OverflowText> : text)}
|
|
87
|
+
</div>
|
|
88
|
+
)}
|
|
87
89
|
{!!actions && <div className={`${eccgui}-graphviz__edge-label__aux`}>{actions}</div>}
|
|
88
90
|
</div>
|
|
89
91
|
);
|