Skip to content

Commit bcae528

Browse files
committed
Merge remote-tracking branch 'origin/develop' into feature/supportProjectVariableAutocompletionForTemplateOperators-CMEM-5572
2 parents a1e815a + 24b73e8 commit bcae528

File tree

17 files changed

+894
-133
lines changed

17 files changed

+894
-133
lines changed

CHANGELOG.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,20 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
1010

1111
- Extended existing height and readOnly props from `CodeEditorProps` to `AutoSuggestionProps` & `ExtendedCodeEditorProps` to be configurable from `<CodeAutocompleteField />`
1212

13+
## [24.3.0] - 2025-06-05
14+
15+
### Added
16+
17+
- added support for React Flow v12
18+
- `<NodeContent />` can used with `flowVersion="v12"`
19+
- more v12-only components: `EdgeDefaultV12`, `NodeDefaultV12`, `EdgeDefs`
20+
- they may be removed in future version when v12 elements are available direcly via `<EdgeDefault />` and `<NodeDefault />`
21+
22+
### Deprecated
23+
24+
- `<EdgeDefaultV12 />` and `<NodeDefaultV12 />` will be removed when React Flow v12 is supported directly by `<EdgeDefault />` and `<NodeDefault />`
25+
- `flowVersion` property: `legacy` and `next` will be removed/replaced by `v##` values
26+
1327
## [24.2.0] - 2025-06-04
1428

1529
### Added

package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@eccenca/gui-elements",
33
"description": "GUI elements based on other libraries, usable in React application, written in Typescript.",
4-
"version": "24.2.0",
4+
"version": "24.3.0",
55
"license": "Apache-2.0",
66
"homepage": "https://github.com/eccenca/gui-elements",
77
"bugs": "https://github.com/eccenca/gui-elements/issues",
@@ -81,6 +81,7 @@
8181
"@codemirror/lang-yaml": "^6.1.2",
8282
"@codemirror/legacy-modes": "^6.5.0",
8383
"@mavrin/remark-typograf": "^2.2.0",
84+
"@xyflow/react": "^12.6.0",
8485
"classnames": "^2.5.1",
8586
"codemirror": "^6.0.1",
8687
"color": "^4.2.3",
@@ -179,6 +180,8 @@
179180
"resolutions": {
180181
"**/@types/react": "^17.0.85",
181182
"node-sass-package-importer/**/postcss": "^8.4.49",
183+
"string-width": "^4.2.3",
184+
"wrap-ansi": "^7.0.0",
182185
"hast-util-from-parse5": "8.0.0"
183186
},
184187
"husky": {

src/components/AutoSuggestion/AutoSuggestion.tsx

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ const AutoSuggestion = ({
214214
const suggestionRequestData = React.useRef<RequestMetaData>({ requestId: undefined });
215215
const [pathValidationPending, setPathValidationPending] = React.useState(false);
216216
const validationRequestData = React.useRef<RequestMetaData>({ requestId: undefined });
217-
const errorMarkers = React.useRef<any[]>([])
217+
const errorMarkers = React.useRef<any[]>([]);
218218
const [validationResponse, setValidationResponse] = useState<CodeAutocompleteFieldValidationResult | undefined>(
219219
undefined
220220
);
@@ -306,26 +306,26 @@ const AutoSuggestion = ({
306306
const parseError = validationResponse?.parseError;
307307
if (cm) {
308308
const clearCurrentErrorMarker = () => {
309-
if(errorMarkers.current.length) {
309+
if (errorMarkers.current.length) {
310310
const [from, to] = errorMarkers.current;
311-
removeMarkFromText({ view: cm, from, to })
312-
errorMarkers.current = []
311+
removeMarkFromText({ view: cm, from, to });
312+
errorMarkers.current = [];
313313
}
314-
}
314+
};
315315
if (parseError) {
316316
const { message, start, end } = parseError;
317317
const { toOffset, fromOffset } = getOffsetRange(cm, start, end);
318-
clearCurrentErrorMarker()
319-
const {from, to} = markText({
318+
clearCurrentErrorMarker();
319+
const { from, to } = markText({
320320
view: cm,
321321
from: fromOffset,
322322
to: toOffset,
323323
className: `${eccgui}-autosuggestion__text--highlighted-error`,
324324
title: message,
325325
});
326-
errorMarkers.current = [from, to]
326+
errorMarkers.current = [from, to];
327327
} else {
328-
clearCurrentErrorMarker()
328+
clearCurrentErrorMarker();
329329
}
330330
}
331331

@@ -454,13 +454,13 @@ const AutoSuggestion = ({
454454
[asyncHandleEditorInputChange, autoCompletionRequestDelay]
455455
);
456456

457-
const handleChange = React.useMemo( () => {
457+
const handleChange = React.useMemo(() => {
458458
return (val: string) => {
459459
value.current = val;
460460
checkValuePathValidity.cancel();
461461
checkValuePathValidity(value.current);
462462
onChange(val);
463-
}
463+
};
464464
}, [onChange, checkValuePathValidity]);
465465

466466
const handleCursorChange = (cursor: number, coords: Rect, scrollinfo: HTMLElement, view: EditorView) => {

src/components/Tooltip/Tooltip.tsx

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -86,16 +86,15 @@ export const Tooltip = ({
8686
}, swapDelayTime);
8787
if (placeholderRef.current !== null) {
8888
const eventType = ev.type === "focusin" ? "focusout" : "mouseleave";
89-
(placeholderRef.current as HTMLElement).addEventListener(
90-
eventType,
91-
() => {
92-
if (eventType === "focusout" && eventMemory.current === "afterfocus" ||
93-
eventType === "mouseleave" && eventMemory.current === "afterhover") {
94-
eventMemory.current = null
95-
}
96-
clearTimeout(swapDelay)
89+
(placeholderRef.current as HTMLElement).addEventListener(eventType, () => {
90+
if (
91+
(eventType === "focusout" && eventMemory.current === "afterfocus") ||
92+
(eventType === "mouseleave" && eventMemory.current === "afterhover")
93+
) {
94+
eventMemory.current = null;
9795
}
98-
);
96+
clearTimeout(swapDelay);
97+
});
9998
}
10099
};
101100
(placeholderRef.current as HTMLElement).addEventListener("mouseenter", swap);

src/extensions/react-flow/_react-flow.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
@import "edges/edges";
44
@import "handles/handles";
55
@import "minimap/minimap";
6+
@import "react-flow_v12";
67

78
.react-flow__background {
89
border: solid 1px $eccgui-color-separation-divider;
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
.react-flow .react-flow__edges svg {
2+
overflow: visible;
3+
position: absolute;
4+
pointer-events: none;
5+
}
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
import { memo } from "react";
2+
import React from "react";
3+
import { BaseEdge, Edge, EdgeProps, EdgeText, getBezierPath, getEdgeCenter } from "@xyflow/react";
4+
5+
import { IntentTypes } from "../../../common/Intent";
6+
import { nodeContentUtils } from "../nodes/NodeContent";
7+
import { NodeHighlightColor } from "../nodes/sharedTypes";
8+
9+
import { edgeDefaultUtils } from "./EdgeDefault";
10+
11+
export type EdgeDefaultV12DataProps = Record<string, unknown> & {
12+
/**
13+
* Overwrites the default style how the edge stroke is displayed.
14+
*/
15+
strokeType?: "solid" | "dashed" | "dotted" | "double" | "doubledashed";
16+
/**
17+
* Feedback state of the node.
18+
*/
19+
intent?: IntentTypes;
20+
/**
21+
* Set the color of used highlights to mark the edge.
22+
*/
23+
highlightColor?: NodeHighlightColor | [NodeHighlightColor, NodeHighlightColor];
24+
/**
25+
* Size of the "glow" effect when the edge is hovered.
26+
*/
27+
pathGlowWidth?: number;
28+
/*
29+
* Direction of the SVG path is inversed.
30+
* This is important for the placement of the markers and the animation movement.
31+
*/
32+
inversePath?: boolean;
33+
/**
34+
* Callback handler that returns a React element used as edge title.
35+
*/
36+
renderLabel?: (edgeCenter: [number, number, number, number]) => React.ReactNode;
37+
/**
38+
* Properties are forwarded to the internally used SVG `g` element.
39+
* Data attributes for test ids coud be included here.
40+
*/
41+
edgeSvgProps?: React.SVGProps<SVGGElement>;
42+
};
43+
44+
/**
45+
* This element cannot be used directly, it must be connected via a `edgeTypes` definition.
46+
* @see https://reactflow.dev/docs/api/nodes/
47+
* @deprecated (v26) will be removed when `EdgeDefault` supports v12 directly
48+
*/
49+
export const EdgeDefaultV12 = memo(
50+
({
51+
id,
52+
sourceX,
53+
sourceY,
54+
targetX,
55+
targetY,
56+
sourcePosition,
57+
targetPosition,
58+
label,
59+
labelStyle,
60+
labelShowBg,
61+
labelBgStyle,
62+
labelBgPadding = [5, 5],
63+
labelBgBorderRadius = 3,
64+
data = {},
65+
...edgeOriginalProperties
66+
}: EdgeProps<Edge<EdgeDefaultV12DataProps>>) => {
67+
const { pathGlowWidth = 10, highlightColor, renderLabel, edgeSvgProps, intent, inversePath, strokeType } = data;
68+
69+
const [edgePath, labelX, labelY] = getBezierPath({
70+
sourceX,
71+
sourceY,
72+
sourcePosition,
73+
targetX,
74+
targetY,
75+
targetPosition,
76+
});
77+
78+
const edgeStyle = edgeOriginalProperties.style ?? {};
79+
const { highlightCustomPropertySettings } = nodeContentUtils.evaluateHighlightColors(
80+
"--edge-highlight",
81+
highlightColor
82+
);
83+
84+
const edgeCenter = getEdgeCenter({
85+
sourceX,
86+
sourceY,
87+
targetX,
88+
targetY,
89+
});
90+
91+
const renderedLabel =
92+
renderLabel?.([labelX, labelY, sourceX, targetX]) ??
93+
(label ? (
94+
<EdgeText
95+
x={edgeCenter[0]}
96+
y={edgeCenter[1]}
97+
label={label}
98+
labelStyle={labelStyle}
99+
labelShowBg={labelShowBg}
100+
labelBgStyle={labelBgStyle}
101+
labelBgPadding={labelBgPadding || [5, 5]}
102+
labelBgBorderRadius={labelBgBorderRadius || 3}
103+
/>
104+
) : null);
105+
106+
return (
107+
<g
108+
className={
109+
"react-flow__edge " +
110+
edgeDefaultUtils.createEdgeDefaultClassName(
111+
{ intent },
112+
`${edgeOriginalProperties.selected ? "selected" : ""}`
113+
)
114+
}
115+
tabIndex={0}
116+
role="button"
117+
data-id={id}
118+
aria-label={`Edge from ${edgeOriginalProperties.source} to ${edgeOriginalProperties.target}`}
119+
aria-describedby={`react-flow__edge-desc-${id}`}
120+
>
121+
<g className={edgeSvgProps?.className ?? ""}>
122+
{highlightColor && (
123+
<path
124+
d={edgePath}
125+
className={edgeDefaultUtils.createEdgeDefaultClassName(
126+
{ highlightColor },
127+
"react-flow__edge-path-highlight"
128+
)}
129+
strokeWidth={10}
130+
style={{
131+
...highlightCustomPropertySettings,
132+
}}
133+
/>
134+
)}
135+
136+
<BaseEdge
137+
id={id}
138+
path={edgePath}
139+
markerStart={inversePath ? "url(#arrow-closed-reverse)" : undefined}
140+
markerEnd={!inversePath ? "url(#arrow-closed)" : undefined}
141+
className={edgeDefaultUtils.createEdgeDefaultClassName({ strokeType })}
142+
interactionWidth={pathGlowWidth}
143+
style={{
144+
...edgeSvgProps?.style,
145+
...edgeStyle,
146+
color: edgeStyle.color || edgeStyle.stroke,
147+
}}
148+
/>
149+
</g>
150+
{renderedLabel}
151+
</g>
152+
);
153+
}
154+
);
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import React from "react";
2+
3+
export const EdgeDefs = React.memo(() => (
4+
<svg style={{ position: "absolute", top: 0, left: 0 }}>
5+
<defs>
6+
<marker
7+
id="arrow-closed"
8+
viewBox="-10 -10 20 20"
9+
markerWidth="10"
10+
markerHeight="10"
11+
refX="0"
12+
refY="0"
13+
orient="auto"
14+
>
15+
<path d="M-4,-4 L4,0 L-4,4 Z" fill="currentColor" />
16+
</marker>
17+
<marker
18+
id="arrow-closed-reverse"
19+
viewBox="-10 -10 20 20"
20+
markerWidth="10"
21+
markerHeight="10"
22+
refX="0"
23+
refY="0"
24+
orient="auto-start-reverse"
25+
>
26+
<path d="M-4,-4 L4,0 L-4,4 Z" fill="currentColor" />
27+
</marker>
28+
</defs>
29+
</svg>
30+
));

src/extensions/react-flow/edges/_edges.scss

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,24 @@ path.react-flow__edge-path {
6262
}
6363
}
6464

65+
path.react-flow__edge-interaction {
66+
fill: none;
67+
stroke: currentcolor;
68+
stroke-linecap: round;
69+
70+
.react-flow__edge & {
71+
stroke-opacity: 0;
72+
}
73+
74+
.react-flow__edge:hover & {
75+
stroke-opacity: $reactflow-edge-stroke-opacity-hover * 0.2;
76+
}
77+
78+
.react-flow__edge.selected & {
79+
stroke-opacity: $reactflow-edge-stroke-opacity-selected * 0.2;
80+
}
81+
}
82+
6583
path.react-flow__edge-path-glow {
6684
fill: none;
6785
stroke: currentcolor;

0 commit comments

Comments
 (0)