@eccenca/gui-elements 23.1.0-easynav.0 → 23.1.0-easynav.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.
Files changed (61) hide show
  1. package/CHANGELOG.md +5 -0
  2. package/dist/cjs/components/Depiction/Depiction.js +13 -13
  3. package/dist/cjs/components/Depiction/Depiction.js.map +1 -1
  4. package/dist/cjs/extensions/react-flow/edges/EdgeDefault.js +20 -5
  5. package/dist/cjs/extensions/react-flow/edges/EdgeDefault.js.map +1 -1
  6. package/dist/cjs/extensions/react-flow/edges/EdgeLabel.js +74 -0
  7. package/dist/cjs/extensions/react-flow/edges/EdgeLabel.js.map +1 -0
  8. package/dist/cjs/extensions/react-flow/edges/edgeTypes.js +10 -9
  9. package/dist/cjs/extensions/react-flow/edges/edgeTypes.js.map +1 -1
  10. package/dist/cjs/extensions/react-flow/handles/HandleDefault.js +10 -2
  11. package/dist/cjs/extensions/react-flow/handles/HandleDefault.js.map +1 -1
  12. package/dist/cjs/extensions/react-flow/index.js +13 -3
  13. package/dist/cjs/extensions/react-flow/index.js.map +1 -1
  14. package/dist/cjs/extensions/react-flow/nodes/NodeContent.js +86 -15
  15. package/dist/cjs/extensions/react-flow/nodes/NodeContent.js.map +1 -1
  16. package/dist/cjs/extensions/react-flow/nodes/NodeDefault.js +2 -1
  17. package/dist/cjs/extensions/react-flow/nodes/NodeDefault.js.map +1 -1
  18. package/dist/cjs/extensions/react-flow/versionsupport.js +17 -0
  19. package/dist/cjs/extensions/react-flow/versionsupport.js.map +1 -1
  20. package/dist/esm/components/Depiction/Depiction.js +15 -14
  21. package/dist/esm/components/Depiction/Depiction.js.map +1 -1
  22. package/dist/esm/extensions/react-flow/edges/EdgeDefault.js +20 -4
  23. package/dist/esm/extensions/react-flow/edges/EdgeDefault.js.map +1 -1
  24. package/dist/esm/extensions/react-flow/edges/EdgeLabel.js +63 -0
  25. package/dist/esm/extensions/react-flow/edges/EdgeLabel.js.map +1 -0
  26. package/dist/esm/extensions/react-flow/edges/edgeTypes.js +10 -9
  27. package/dist/esm/extensions/react-flow/edges/edgeTypes.js.map +1 -1
  28. package/dist/esm/extensions/react-flow/handles/HandleDefault.js +10 -2
  29. package/dist/esm/extensions/react-flow/handles/HandleDefault.js.map +1 -1
  30. package/dist/esm/extensions/react-flow/index.js +2 -1
  31. package/dist/esm/extensions/react-flow/index.js.map +1 -1
  32. package/dist/esm/extensions/react-flow/nodes/NodeContent.js +94 -21
  33. package/dist/esm/extensions/react-flow/nodes/NodeContent.js.map +1 -1
  34. package/dist/esm/extensions/react-flow/nodes/NodeDefault.js +2 -1
  35. package/dist/esm/extensions/react-flow/nodes/NodeDefault.js.map +1 -1
  36. package/dist/esm/extensions/react-flow/versionsupport.js +31 -1
  37. package/dist/esm/extensions/react-flow/versionsupport.js.map +1 -1
  38. package/dist/types/extensions/react-flow/edges/EdgeDefault.d.ts +16 -1
  39. package/dist/types/extensions/react-flow/edges/EdgeLabel.d.ts +44 -0
  40. package/dist/types/extensions/react-flow/edges/edgeTypes.d.ts +10 -9
  41. package/dist/types/extensions/react-flow/index.d.ts +2 -2
  42. package/dist/types/extensions/react-flow/nodes/NodeContent.d.ts +40 -3
  43. package/dist/types/extensions/react-flow/versionsupport.d.ts +2 -1
  44. package/package.json +1 -1
  45. package/src/cmem/react-flow/ReactFlow/ReactFlow.stories.tsx +2 -2
  46. package/src/cmem/react-flow/_edges.scss +3 -2
  47. package/src/components/Depiction/Depiction.tsx +11 -10
  48. package/src/extensions/react-flow/_config.scss +8 -4
  49. package/src/extensions/react-flow/edges/EdgeDefault.tsx +60 -5
  50. package/src/extensions/react-flow/edges/EdgeLabel.tsx +127 -0
  51. package/src/extensions/react-flow/edges/_edges.scss +206 -31
  52. package/src/extensions/react-flow/edges/edgeTypes.ts +13 -9
  53. package/src/extensions/react-flow/edges/stories/EdgeDefault.stories.tsx +34 -13
  54. package/src/extensions/react-flow/edges/stories/EdgeLabel.stories.tsx +39 -0
  55. package/src/extensions/react-flow/handles/HandleDefault.tsx +18 -11
  56. package/src/extensions/react-flow/index.ts +3 -2
  57. package/src/extensions/react-flow/nodes/NodeContent.tsx +161 -26
  58. package/src/extensions/react-flow/nodes/NodeDefault.tsx +2 -2
  59. package/src/extensions/react-flow/nodes/_nodes.scss +220 -60
  60. package/src/extensions/react-flow/nodes/stories/NodeContent.stories.tsx +62 -1
  61. package/src/extensions/react-flow/versionsupport.ts +17 -1
@@ -1,17 +1,20 @@
1
1
  import React from "react";
2
+ import Color from "color";
2
3
  import { Position, useStoreState as useStoreStateFlowLegacy } from "react-flow-renderer";
3
4
  import { useStore as useStoreStateFlowNext } from "react-flow-renderer-lts";
4
- import { Icon, Depiction } from "../../../index";
5
+ import { Icon, Depiction, OverflowText } from "../../../index";
5
6
  import { CLASSPREFIX as eccgui } from "../../../configuration/constants";
6
7
  import { ValidIconName } from "../../../components/Icon/canonicalIconNames";
7
8
  import { DepictionProps } from "../../../components/Depiction/Depiction";
8
- import { ReacFlowVersionSupportProps } from "../versionsupport";
9
+ import { IntentTypes, intentClassName } from "../../../common/Intent";
10
+ import { ReacFlowVersionSupportProps, useReactFlowVersion } from "../versionsupport";
9
11
  import { HandleDefault, HandleProps, HandleNextProps } from "./../handles/HandleDefault";
10
12
  import { NodeProps } from "./NodeDefault";
11
13
  import { NodeContentExtensionProps } from "./NodeContentExtension";
12
14
  import { Resizable } from "re-resizable";
13
15
 
14
16
  export type HighlightingState = "success" | "warning" | "danger" | "match" | "altmatch";
17
+ export type NodeHighlightColor = "default" | "alternate" | Color | string;
15
18
 
16
19
  export interface IHandleProps extends HandleProps {
17
20
  category?: "configuration";
@@ -44,7 +47,11 @@ interface NodeContentData<CONTENT_PROPS = any> {
44
47
  /**
45
48
  * Label that is displayed in the node header.
46
49
  */
47
- label: string;
50
+ label: string | JSX.Element;
51
+ /**
52
+ * Element that is displayed as subline under the label in the header.
53
+ */
54
+ labelSubline?: JSX.Element;
48
55
  /**
49
56
  * Content element, displayed in the node body.
50
57
  */
@@ -73,9 +80,35 @@ export interface NodeContentProps<NODE_DATA, NODE_CONTENT_PROPS = any>
73
80
  */
74
81
  minimalShape?: "none" | "circular" | "rectangular";
75
82
  /**
83
+ * Stretches the node to the full available width.
84
+ */
85
+ fullWidth?: boolean;
86
+ /**
87
+ * Increase the hight of the node header.
88
+ * Use this for example if you need more space for a label subline.
89
+ * Also the depiction is displayed larger.
90
+ */
91
+ enlargeHeader?: boolean;
92
+ /**
93
+ * @deprecated
76
94
  * Set the type of used highlights to mark the node.
95
+ * Replaced by `intent` and `highlightColor` properties.
77
96
  */
78
97
  highlightedState?: HighlightingState | HighlightingState[];
98
+ /**
99
+ * Defines how the borders of a node are displayed.
100
+ * Use this property to overwrite default styles.
101
+ * You can use this to visuaize different states or type without depending only on color.
102
+ */
103
+ border?: "solid" | "double" | "dashed" | "dotted";
104
+ /**
105
+ * Feedback state of the node.
106
+ */
107
+ intent?: IntentTypes;
108
+ /**
109
+ * Set the type of used highlights to mark the node.
110
+ */
111
+ highlightColor?: NodeHighlightColor | [NodeHighlightColor, NodeHighlightColor];
79
112
  /**
80
113
  * Text used for tooltip used on icon and depiction.
81
114
  */
@@ -181,7 +214,17 @@ interface MemoHandlerNextProps extends HandleNextProps {
181
214
 
182
215
  type MemoHandlerProps = MemoHandlerLegacyProps | MemoHandlerNextProps;
183
216
 
184
- const defaultHandles = [{ type: "target" }, { type: "source" }] as IHandleProps[];
217
+ const defaultHandles = () => {
218
+ const flowVersion = useReactFlowVersion();
219
+ switch (flowVersion) {
220
+ case "legacy":
221
+ return [{ type: "target" }, { type: "source" }] as IHandleProps[];
222
+ case "next":
223
+ return [{ type: "target" }, { type: "source" }] as NodeContentHandleNextProps[];
224
+ default:
225
+ return [];
226
+ }
227
+ }
185
228
 
186
229
  const getDefaultMinimalTooltipData = (node: any) => {
187
230
  return {
@@ -216,10 +259,14 @@ const addHandles = (handles: any, position: any, posDirection: any, isConnectabl
216
259
  });
217
260
  };
218
261
 
219
- export const gethighlightedStateClasses = (state: any, baseClassName: any) => {
262
+ export const gethighlightedStateClasses = (
263
+ state: HighlightingState | HighlightingState[],
264
+ baseClassName: string
265
+ ) => {
220
266
  let hightlights = typeof state === "string" ? [state] : state;
221
- //@ts-ignore
222
- return hightlights.map((item) => `${baseClassName}--highlight-${item}`).join(" ");
267
+ return hightlights.map(
268
+ (item : HighlightingState) => `${baseClassName}--highlight-${item}`
269
+ ).join(" ");
223
270
  };
224
271
 
225
272
  const MemoHandler = React.memo(
@@ -235,22 +282,28 @@ const MemoHandler = React.memo(
235
282
  * This element cannot be used directly, all properties must be routed through the `data` property of an `elements` property item inside the `ReactFlow` container.
236
283
  */
237
284
  export function NodeContent<CONTENT_PROPS = any>({
238
- flowVersion = "legacy",
285
+ flowVersion = useReactFlowVersion(),
239
286
  iconName,
240
287
  depiction,
241
288
  leftElement,
242
289
  typeLabel,
243
290
  label,
291
+ labelSubline,
292
+ enlargeHeader,
293
+ fullWidth,
244
294
  showExecutionButtons = true,
245
295
  executionButtons,
246
296
  menuButtons,
247
297
  content,
248
298
  contentExtension,
249
- footerContent,
299
+ footerContent,
250
300
  size = "small",
251
301
  minimalShape = "circular",
252
302
  highlightedState,
253
- handles = defaultHandles,
303
+ intent,
304
+ border,
305
+ highlightColor,
306
+ handles = defaultHandles(),
254
307
  adaptHeightForHandleMinCount,
255
308
  adaptSizeIncrement = 15,
256
309
  getMinimalTooltipData = getDefaultMinimalTooltipData,
@@ -270,11 +323,15 @@ export function NodeContent<CONTENT_PROPS = any>({
270
323
  // other props for DOM element
271
324
  ...otherProps
272
325
  }: NodeContentProps<any>) {
326
+ const isResizeable = (!!onNodeResize && minimalShape === "none");
273
327
  const [width, setWidth] = React.useState<number>(nodeDimensions?.width ?? 0);
274
328
  const [height, setHeight] = React.useState<number>(nodeDimensions?.height ?? 0);
275
- const [, , zoom] = flowVersion === "legacy"
276
- ? useStoreStateFlowLegacy((state) => state.transform)
277
- : useStoreStateFlowNext((state) => state.transform);
329
+ let zoom = 1;
330
+ if (isResizeable) try {
331
+ [, , zoom] = flowVersion === "legacy"
332
+ ? useStoreStateFlowLegacy((state) => state.transform)
333
+ : useStoreStateFlowNext((state) => state.transform);
334
+ } catch {}
278
335
  const [adjustedContentProps, setAdjustedContentProps] = React.useState<Partial<CONTENT_PROPS>>({});
279
336
  const nodeContentRef = React.useRef<any>();
280
337
  const handleStack = flowVersion==="legacy" ? {} as { [key: string]: IHandleProps[] } : {} as { [key: string]: NodeContentHandleNextProps[] };
@@ -335,17 +392,29 @@ export function NodeContent<CONTENT_PROPS = any>({
335
392
  styleExpandDimensions["minHeight"] = Math.max(minHeightLeft, minHeightRight);
336
393
  }
337
394
 
395
+ const {
396
+ highlightClassNameSuffix,
397
+ highlightCustomPropertySettings
398
+ } = evaluateHighlightColors("--node-highlight", highlightColor);
399
+
338
400
  const resizableStyles = (!!onNodeResize === true && minimalShape === "none" && (width + height > 0)) ? { width, height } : {};
339
401
  const nodeContent = (
340
402
  <>
341
403
  <section
342
404
  ref={nodeContentRef}
343
405
  {...otherProps}
344
- style={{ ...style, ...styleExpandDimensions, ...resizableStyles }}
406
+ style={{ ...style, ...highlightCustomPropertySettings, ...styleExpandDimensions, ...resizableStyles }}
345
407
  className={
346
408
  `${eccgui}-graphviz__node` +
347
409
  ` ${eccgui}-graphviz__node--${size}` +
348
410
  ` ${eccgui}-graphviz__node--minimal-${minimalShape}` +
411
+ (fullWidth ? ` ${eccgui}-graphviz__node--fullwidth` : "") +
412
+ (border ? ` ${eccgui}-graphviz__node--border-${border}` : "") +
413
+ (intent ? ` ${intentClassName(intent)}` : "") +
414
+ (highlightClassNameSuffix.length > 0
415
+ ? highlightClassNameSuffix.map(highlight => ` ${eccgui}-graphviz__node--highlight-${highlight}`).join("")
416
+ : ""
417
+ ) +
349
418
  (!!highlightedState
350
419
  ? " " + gethighlightedStateClasses(highlightedState, `${eccgui}-graphviz__node`)
351
420
  : "") +
@@ -354,9 +423,12 @@ export function NodeContent<CONTENT_PROPS = any>({
354
423
  (letPassWheelEvents === false ? ` nowheel` : "")
355
424
  }
356
425
  >
357
- <header className={`${eccgui}-graphviz__node__header`}>
426
+ <header className={
427
+ `${eccgui}-graphviz__node__header` +
428
+ ((enlargeHeader && minimalShape==="none") ? ` ${eccgui}-graphviz__node__header--large` : "")
429
+ }>
358
430
  {(!!iconName || !!depiction || !!leftElement) && (
359
- <span className={`${eccgui}-graphviz__node__header-depiction`}>
431
+ <div className={`${eccgui}-graphviz__node__header-depiction`}>
360
432
  { leftElement }
361
433
  {!!depiction && !leftElement && typeof depiction === "string" && (
362
434
  <Depiction
@@ -380,23 +452,37 @@ export function NodeContent<CONTENT_PROPS = any>({
380
452
  })
381
453
  )}
382
454
  {!!iconName && !leftElement && !depiction && (
383
- <Icon
384
- name={iconName}
385
- tooltipText={minimalShape === "none" || selected ? typeLabel : undefined}
455
+ <Depiction
456
+ image={<Icon name={iconName} />}
457
+ caption={minimalShape === "none" || selected ? typeLabel : undefined}
458
+ captionPosition="tooltip"
459
+ padding="tiny"
460
+ ratio="1:1"
461
+ resizing="contain"
462
+ forceInlineSvg
386
463
  />
387
464
  )}
388
- </span>
465
+ </div>
389
466
  )}
390
- <span className={`${eccgui}-graphviz__node__header-label`} title={label}>
391
- {label}
392
- </span>
467
+ <div className={`${eccgui}-graphviz__node__header-label`} title={typeof label==="string" ? label : undefined}>
468
+ {
469
+ typeof label === "string"
470
+ ? <OverflowText className={`${eccgui}-graphviz__node__header-label__mainline`}>{label}</OverflowText>
471
+ : <div className={`${eccgui}-graphviz__node__header-label__mainline`}>{label}</div>
472
+ }
473
+ {!!labelSubline && (
474
+ <div className={`${eccgui}-graphviz__node__header-label__subline`}>
475
+ { labelSubline }
476
+ </div>
477
+ )}
478
+ </div>
393
479
  {(menuButtons || (showExecutionButtons && executionButtons)) && (
394
- <span className={`${eccgui}-graphviz__node__header-menu`}>
480
+ <div className={`${eccgui}-graphviz__node__header-menu`}>
395
481
  {showExecutionButtons && typeof executionButtons === "function"
396
482
  ? executionButtons(adjustedContentProps, setAdjustedContentProps)
397
483
  : null}
398
484
  {menuButtons ?? null}
399
- </span>
485
+ </div>
400
486
  )}
401
487
  </header>
402
488
  {content && (
@@ -449,5 +535,54 @@ export function NodeContent<CONTENT_PROPS = any>({
449
535
  </Resizable>
450
536
  );
451
537
 
452
- return (!!onNodeResize && minimalShape === "none") ? resizableNode() : nodeContent;
538
+ return (isResizeable) ? resizableNode() : nodeContent;
539
+ }
540
+
541
+ export const evaluateHighlightColors = (
542
+ baseCustomProperty: string,
543
+ highlightColor?: NodeHighlightColor | NodeHighlightColor[]
544
+ ) => {
545
+ let styleHighlightColors = {
546
+ [`${baseCustomProperty}-default-color`]: undefined,
547
+ [`${baseCustomProperty}-alternate-color`]: undefined,
548
+ } as React.CSSProperties;
549
+ const classesHightlightColors = [] as string[];
550
+ if (!!highlightColor) {
551
+ const highlightingColors = (typeof highlightColor === "string") ? [highlightColor] : highlightColor;
552
+ (highlightingColors as Array<string>).map((color, idx) => {
553
+ switch (color) {
554
+ case "default":
555
+ classesHightlightColors.push("default");
556
+ break;
557
+ case "alternate":
558
+ classesHightlightColors.push("alternate");
559
+ break;
560
+ default:
561
+ classesHightlightColors.push("custom");
562
+ let customColor = Color("#ffffff")
563
+ try {
564
+ customColor = Color(color);
565
+ } catch(ex) {
566
+ console.warn("Received invalid color for highlight: " + color)
567
+ }
568
+ if (idx === 0) {
569
+ styleHighlightColors = {
570
+ ...styleHighlightColors,
571
+ [`${baseCustomProperty}-default-color`]: customColor.rgb().toString(),
572
+ } as React.CSSProperties
573
+ } else {
574
+ styleHighlightColors = {
575
+ ...styleHighlightColors,
576
+ [`${baseCustomProperty}-alternate-color`]: customColor.rgb().toString(),
577
+ } as React.CSSProperties
578
+ }
579
+ break;
580
+ }
581
+ });
582
+ }
583
+
584
+ return {
585
+ highlightClassNameSuffix: classesHightlightColors,
586
+ highlightCustomPropertySettings: styleHighlightColors,
587
+ }
453
588
  }
@@ -5,7 +5,7 @@ import {
5
5
  } from "react-flow-renderer";
6
6
  import { Tooltip } from "../../../index";
7
7
  import { NodeContent, NodeContentProps } from "./NodeContent";
8
- import { ReacFlowVersionSupportProps } from "../versionsupport";
8
+ import { ReacFlowVersionSupportProps, useReactFlowVersion } from "../versionsupport";
9
9
 
10
10
  export interface NodeProps<NODE_DATA, NODE_CONTENT_PROPS = any> extends ReacFlowVersionSupportProps, ReactFlowNodeProps {
11
11
  /**
@@ -23,7 +23,7 @@ export interface NodeProps<NODE_DATA, NODE_CONTENT_PROPS = any> extends ReacFlow
23
23
  export const NodeDefault = memo(
24
24
  (node: NodeProps<any>) => {
25
25
  const {
26
- flowVersion,
26
+ flowVersion = useReactFlowVersion(),
27
27
  data,
28
28
  targetPosition = Position.Left,
29
29
  sourcePosition = Position.Right,
@@ -51,22 +51,6 @@
51
51
  }
52
52
  }
53
53
 
54
- .#{$eccgui}-graphviz__node--animated {
55
- animation: pumpingshadow 4 * $reactflow-transition-time linear infinite;
56
- }
57
-
58
- @keyframes pumpingshadow {
59
- 0% {
60
- box-shadow: 0 0 2 * $reactflow-node-border-width 0 rgba(#fff, 0.9), 0 0 1 * $reactflow-node-border-width 0 rgba($reactflow-edge-stroke-color-selected, 0);
61
- }
62
- 50% {
63
- box-shadow: 0 0 2 * $reactflow-node-border-width 6 * $reactflow-node-border-width rgba(#fff, 0.9), 0 0 1 * $reactflow-node-border-width 6 * $reactflow-node-border-width $reactflow-edge-stroke-color-selected;
64
- }
65
- 100% {
66
- box-shadow: 0 0 2 * $reactflow-node-border-width 0 rgba(#fff, 0.9), 0 0 1 * $reactflow-node-border-width 0 rgba($reactflow-edge-stroke-color-selected, 0);
67
- }
68
- }
69
-
70
54
  .#{$eccgui}-graphviz__node--minimal-rectangular,
71
55
  .#{$eccgui}-graphviz__node--minimal-circular {
72
56
 
@@ -120,22 +104,20 @@
120
104
  }
121
105
  }
122
106
 
107
+ .#{$eccgui}-graphviz__node__header--large {
108
+ min-height: $reactflow-node-largesize;
109
+ }
110
+
123
111
  .#{$eccgui}-graphviz__node__header-depiction,
124
112
  .#{$eccgui}-graphviz__node__header-menu {
125
113
  flex-grow: 0;
126
114
  flex-shrink: 0;
127
115
  max-height: calc(#{$reactflow-node-basesize} - #{2 * $reactflow-node-border-width});
128
- }
129
-
130
- .#{$eccgui}-graphviz__node__header-label {
131
116
  margin: 0 $eccgui-size-block-whitespace * 0.25;
132
- white-space: nowrap;
133
- overflow: hidden;
134
- text-overflow: ellipsis;
135
- flex-grow: 1;
136
- flex-shrink: 1;
137
- display: inline-block;
138
- text-align: left;
117
+
118
+ .#{$eccgui}-graphviz__node__header--large & {
119
+ max-height: calc(#{$reactflow-node-largesize} - #{2 * $reactflow-node-border-width});
120
+ }
139
121
  }
140
122
 
141
123
  .#{$eccgui}-graphviz__node__header-depiction {
@@ -165,6 +147,37 @@
165
147
  height: calc(#{$reactflow-node-basesize} - #{2 * $reactflow-node-border-width});
166
148
  }
167
149
  }
150
+
151
+ .#{$eccgui}-graphviz__node__header--large & {
152
+ min-width: calc(#{$reactflow-node-largesize} - #{2 * $reactflow-node-border-width});
153
+ min-height: calc(#{$reactflow-node-largesize} - #{2 * $reactflow-node-border-width});
154
+ max-width: calc(2 * (#{$reactflow-node-largesize} - #{2 * $reactflow-node-border-width}));
155
+
156
+ .#{$eccgui}-depiction__image {
157
+ height: calc(#{$reactflow-node-largesize} - #{2 * $reactflow-node-border-width});
158
+ }
159
+ }
160
+ }
161
+
162
+ .#{$eccgui}-graphviz__node__header-label {
163
+ margin: 0 $eccgui-size-block-whitespace * 0.25;
164
+ white-space: nowrap;
165
+ overflow: hidden;
166
+ text-overflow: ellipsis;
167
+ flex-grow: 1;
168
+ flex-shrink: 1;
169
+ display: inline-flex;
170
+ flex-direction: column;
171
+ text-align: left;
172
+ }
173
+
174
+ .#{$eccgui}-graphviz__node__header-label__mainline,
175
+ .#{$eccgui}-graphviz__node__header-label__subline {
176
+ overflow: hidden;
177
+ text-overflow: ellipsis;
178
+ white-space: nowrap;
179
+ flex-grow: 0;
180
+ flex-shrink: 0;
168
181
  }
169
182
 
170
183
  .#{$eccgui}-graphviz__node__content {
@@ -231,12 +244,47 @@
231
244
  max-height: $reactflow-node-basesize * 13;
232
245
  }
233
246
 
234
- // Node highlights
247
+ .#{$eccgui}-graphviz__node--fullwidth:not(.is-resizeable) {
248
+ width: 100%;
249
+ }
235
250
 
236
- .#{$eccgui}-graphviz__node--highlight-success,
237
- .#{$eccgui}-graphviz__node--highlight-warning,
238
- .#{$eccgui}-graphviz__node--highlight-danger {
239
- &:before {
251
+ // Node border overwrites
252
+
253
+ .#{$eccgui}-graphviz__node--border-solid {
254
+ border-style: solid;
255
+ }
256
+
257
+ .#{$eccgui}-graphviz__node--border-double {
258
+ border-width: 1.5 * $reactflow-node-border-width;
259
+ border-style: double;
260
+ }
261
+
262
+ .#{$eccgui}-graphviz__node--border-dashed {
263
+ border-style: dashed;
264
+ }
265
+
266
+ .#{$eccgui}-graphviz__node--border-dotted {
267
+ border-style: dotted;
268
+ }
269
+
270
+ // Node intent
271
+
272
+ @mixin node-intent-gradient {
273
+ border-image-source: conic-gradient(
274
+ from var(--node-intent-angle),
275
+ transparent,
276
+ var(--node-intent-color) 0.05turn,
277
+ var(--node-intent-color) 0.2turn,
278
+ transparent 0.25turn
279
+ );
280
+ }
281
+
282
+ .#{$eccgui}-graphviz__node[class*="#{$eccgui}-intent--"],
283
+ .#{$eccgui}-graphviz__node--animated:not([class*="#{$eccgui}-intent--"]) {
284
+ --node-intent-color: #{$eccgui-color-workspace-text};
285
+
286
+ &:after {
287
+ --node-intent-angle: #{$reactflow-transition-anglestart};
240
288
  content: " ";
241
289
  display: block;
242
290
  position: absolute;
@@ -244,15 +292,45 @@
244
292
  left: -2 * $reactflow-node-border-width;
245
293
  bottom: -2 * $reactflow-node-border-width;
246
294
  right: -2 * $reactflow-node-border-width;
247
- border-radius: inherit;
248
- box-shadow: 0 0 0 2 * $reactflow-node-border-width $eccgui-color-danger-text;
249
295
  z-index: -1;
296
+ border-style: solid;
297
+ border-width: 2 * $reactflow-node-border-width;
298
+ @include node-intent-gradient;
299
+ border-image-slice: 1;
300
+ border-image-width: 2 * $reactflow-node-border-width;
250
301
  }
251
302
  }
252
303
 
253
- .#{$eccgui}-graphviz__node--highlight-match,
254
- .#{$eccgui}-graphviz__node--highlight-altmatch {
255
- &:after {
304
+ .#{$eccgui}-graphviz__node.#{$eccgui}-intent--primary {
305
+ --node-intent-color: #{$eccgui-color-primary};
306
+ }
307
+
308
+ .#{$eccgui}-graphviz__node.#{$eccgui}-intent--accent {
309
+ --node-intent-color: #{$eccgui-color-accent};
310
+ }
311
+
312
+ .#{$eccgui}-graphviz__node.#{$eccgui}-intent--info {
313
+ --node-intent-color: #{$eccgui-color-info-text};
314
+ }
315
+
316
+ .#{$eccgui}-graphviz__node.#{$eccgui}-intent--success {
317
+ --node-intent-color: #{$eccgui-color-success-text};
318
+ }
319
+
320
+ .#{$eccgui}-graphviz__node.#{$eccgui}-intent--warning {
321
+ --node-intent-color: #{$eccgui-color-warning-text};
322
+ }
323
+
324
+ .#{$eccgui}-graphviz__node.#{$eccgui}-intent--danger {
325
+ --node-intent-color: #{$eccgui-color-danger-text};
326
+ }
327
+
328
+ // hode highlight mark
329
+
330
+ .#{$eccgui}-graphviz__node[class*="#{$eccgui}-graphviz__node--highlight-"] {
331
+
332
+ &:before {
333
+ opacity: $eccgui-opacity-disabled;
256
334
  content: " ";
257
335
  display: block;
258
336
  position: absolute;
@@ -260,38 +338,56 @@
260
338
  left: -2 * $reactflow-node-border-width;
261
339
  bottom: -2 * $reactflow-node-border-width;
262
340
  right: -2 * $reactflow-node-border-width;
263
- border-radius: inherit;
264
- box-shadow: 0 0 0 2 * $reactflow-node-border-width $eccgui-color-accent;
265
- z-index: -1;
341
+ z-index: -2;
342
+ box-shadow:
343
+ 0 0 0 2 * $reactflow-node-border-width var(--node-highlight-default-color),
344
+ 0 0 0 3.5 * $reactflow-node-border-width var(--node-highlight-alternate-color, var(--node-highlight-default-color));
345
+ border: 0.1px solid transparent; // workaround for Firefox, otherwise shadows are overlayed
266
346
  }
347
+ }
267
348
 
268
- &.#{$eccgui}-graphviz__node--highlight-success,
269
- &.#{$eccgui}-graphviz__node--highlight-warning,
270
- &.#{$eccgui}-graphviz__node--highlight-danger {
271
- &:after {
272
- top: -4 * $reactflow-node-border-width;
273
- left: -4 * $reactflow-node-border-width;
274
- bottom: -4 * $reactflow-node-border-width;
275
- right: -4 * $reactflow-node-border-width;
276
- }
277
- }
349
+ .#{$eccgui}-graphviz__node--highlight-default {
350
+ --node-highlight-default-color: #{$eccgui-color-accent};
351
+ --node-highlight-alternate-color: #{$eccgui-color-accent};
278
352
  }
279
353
 
280
- .#{$eccgui}-graphviz__node--highlight-success {
281
- &:before {
282
- box-shadow: 0 0 0 2 * $reactflow-node-border-width $eccgui-color-success-text;
283
- }
354
+ .#{$eccgui}-graphviz__node--highlight-alternate {
355
+ --node-highlight-default-color: #{$eccgui-color-primary};
356
+ --node-highlight-alternate-color: #{$eccgui-color-primary};
284
357
  }
285
358
 
286
- .#{$eccgui}-graphviz__node--highlight-warning {
287
- &:before {
288
- box-shadow: 0 0 0 2 * $reactflow-node-border-width $eccgui-color-warning-text;
289
- }
359
+ .#{$eccgui}-graphviz__node--highlight-default.#{$eccgui}-graphviz__node--highlight-alternate {
360
+ --node-highlight-default-color: #{$eccgui-color-accent};
361
+ --node-highlight-alternate-color: #{$eccgui-color-primary};
290
362
  }
291
363
 
292
- .#{$eccgui}-graphviz__node--highlight-altmatch {
293
- &:after {
294
- box-shadow: 0 0 0 2 * $reactflow-node-border-width complement($eccgui-color-primary);
364
+ // Node animation
365
+
366
+ @property --node-intent-angle {
367
+ // rule necessary, otherwise increasing --node-intent-angle for animation does not work correctly
368
+ syntax: '<angle>';
369
+ initial-value: #{$reactflow-transition-anglestart};
370
+ inherits: true;
371
+ }
372
+
373
+ .#{$eccgui}-graphviz__node--animated:after {
374
+ animation: spinningborder 8 * $reactflow-transition-time linear infinite;
375
+
376
+ @keyframes spinningborder {
377
+ to {
378
+ --node-intent-angle: #{$reactflow-transition-anglestart + 360deg};
379
+ }
380
+ @for $step from 1 through 10 {
381
+ /*
382
+ This is a fix/workaround for Firefox/Gecko.
383
+ Looks like "animation" the custom property is not enough.
384
+ It is also necessary to repeat the rule.
385
+ */
386
+ #{$step*10}#{"%"} {
387
+ --node-intent-angle: #{$reactflow-transition-anglestart + $step * 36deg};
388
+ @include node-intent-gradient;
389
+ }
390
+ }
295
391
  }
296
392
  }
297
393
 
@@ -391,3 +487,67 @@
391
487
  flex-grow: 0;
392
488
  flex-shrink: 0;
393
489
  }
490
+
491
+ // Node highlights (@deprecated) // FIXME: remove in v24.0.0
492
+
493
+ .#{$eccgui}-graphviz__node--highlight-success,
494
+ .#{$eccgui}-graphviz__node--highlight-warning,
495
+ .#{$eccgui}-graphviz__node--highlight-danger {
496
+ &:before {
497
+ content: " ";
498
+ display: block;
499
+ position: absolute;
500
+ top: -2 * $reactflow-node-border-width;
501
+ left: -2 * $reactflow-node-border-width;
502
+ bottom: -2 * $reactflow-node-border-width;
503
+ right: -2 * $reactflow-node-border-width;
504
+ border-radius: inherit;
505
+ box-shadow: 0 0 0 2 * $reactflow-node-border-width $eccgui-color-danger-text;
506
+ z-index: -1;
507
+ }
508
+ }
509
+
510
+ .#{$eccgui}-graphviz__node--highlight-match,
511
+ .#{$eccgui}-graphviz__node--highlight-altmatch {
512
+ &:after {
513
+ content: " ";
514
+ display: block;
515
+ position: absolute;
516
+ top: -2 * $reactflow-node-border-width;
517
+ left: -2 * $reactflow-node-border-width;
518
+ bottom: -2 * $reactflow-node-border-width;
519
+ right: -2 * $reactflow-node-border-width;
520
+ border-radius: inherit;
521
+ box-shadow: 0 0 0 2 * $reactflow-node-border-width $eccgui-color-accent;
522
+ z-index: -1;
523
+ }
524
+
525
+ &.#{$eccgui}-graphviz__node--highlight-success,
526
+ &.#{$eccgui}-graphviz__node--highlight-warning,
527
+ &.#{$eccgui}-graphviz__node--highlight-danger {
528
+ &:after {
529
+ top: -4 * $reactflow-node-border-width;
530
+ left: -4 * $reactflow-node-border-width;
531
+ bottom: -4 * $reactflow-node-border-width;
532
+ right: -4 * $reactflow-node-border-width;
533
+ }
534
+ }
535
+ }
536
+
537
+ .#{$eccgui}-graphviz__node--highlight-success {
538
+ &:before {
539
+ box-shadow: 0 0 0 2 * $reactflow-node-border-width $eccgui-color-success-text;
540
+ }
541
+ }
542
+
543
+ .#{$eccgui}-graphviz__node--highlight-warning {
544
+ &:before {
545
+ box-shadow: 0 0 0 2 * $reactflow-node-border-width $eccgui-color-warning-text;
546
+ }
547
+ }
548
+
549
+ .#{$eccgui}-graphviz__node--highlight-altmatch {
550
+ &:after {
551
+ box-shadow: 0 0 0 2 * $reactflow-node-border-width complement($eccgui-color-primary);
552
+ }
553
+ }