Skip to content

Commit 89dde0b

Browse files
authored
Merge pull request #290 from eccenca/release/v24.3.0
Release v24.3.0 into main branch
2 parents 3059cc0 + d07958e commit 89dde0b

File tree

19 files changed

+901
-136
lines changed

19 files changed

+901
-136
lines changed

.github/workflows/publish-final-release.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,12 +72,12 @@ jobs:
7272
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
7373
head: maintain/mergeReleaseTag-v${{ steps.package-version.outputs.version }}
7474
base: ${{ steps.dispatched-branch.outputs.targetbranch }}
75-
title: Release process changes from v${{ steps.create-version.outputs.version }}
75+
title: Release process changes from v${{ steps.package-version.outputs.version }}
7676
draft: true
7777
reviewers: ${{ github.actor }}
7878
body: |
7979
Created by Github workflow.
80-
After merging this PR the "publish final release" action can be triggered on `${{ steps.dispatched-branch.outputs.targetbranch }}`.
80+
Necessary to merge back all changes that had to be done during release process.
8181
8282
publish-package:
8383
needs: publish-final-release

.github/workflows/push-tagged-release.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,13 @@ jobs:
7777
if: inputs.onlyNpmPush != true
7878
run: |
7979
touch ./releasecontent.md
80+
CHANGELOG=$(cat <<"EOL"
81+
${{ steps.info-changelog.outputs.changes }}
82+
EOL
83+
)
8084
echo "* NPM package: https://www.npmjs.com/package/@eccenca/gui-elements/v/${{ steps.info-vars.outputs.version }}" >> ./releasecontent.md
8185
$( if [[ ! "${{ inputs.sectionChangelog }}" =~ ^(Unreleased)$ ]]; then echo "* Storybook: ${{ steps.chromatic-upload.outputs.storybookUrl }}" >> ./releasecontent.md; fi )
82-
$( if [[ ! "${{ inputs.sectionChangelog }}" =~ ^(Unreleased)$ ]]; then echo "${{ steps.info-changelog.outputs.changes }}" >> ./releasecontent.md; else echo "* Changelog: https://github.com/eccenca/gui-elements/blob/${{ inputs.ref }}/CHANGELOG.md#unreleased" >> ./releasecontent.md; fi )
86+
$( if [[ ! "${{ inputs.sectionChangelog }}" =~ ^(Unreleased)$ ]]; then echo "${CHANGELOG}" >> ./releasecontent.md; else echo "* Changelog: https://github.com/eccenca/gui-elements/blob/${{ inputs.ref }}/CHANGELOG.md#unreleased" >> ./releasecontent.md; fi )
8387
- name: Publish release
8488
# only use for final releases and RCs -- other pre-releases do not need an official announcement
8589
if: inputs.onlyNpmPush != true

CHANGELOG.md

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

99
### Added
1010

11+
- added support for React Flow v12
12+
- `<NodeContent />` can used with `flowVersion="v12"`
13+
- more v12-only components: `EdgeDefaultV12`, `NodeDefaultV12`, `EdgeDefs`
14+
- they may be removed in future version when v12 elements are available direcly via `<EdgeDefault />` and `<NodeDefault />`
15+
16+
### Deprecated
17+
18+
- `<EdgeDefaultV12 />` and `<NodeDefaultV12 />` will be removed when React Flow v12 is supported directly by `<EdgeDefault />` and `<NodeDefault />`
19+
- `flowVersion`: `legacy` and `next` will be removed/replaced by `v##` values
20+
21+
## [24.2.0] - 2025-06-04
22+
23+
### Added
24+
1125
- `<ContextOverlay />`
1226
- `usePlaceholder` property: can be used to display the target but include the component later when the first interaction happens, this can improve performance
1327
- `<ContextMenu />`

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
@@ -208,7 +208,7 @@ const AutoSuggestion = ({
208208
const suggestionRequestData = React.useRef<RequestMetaData>({ requestId: undefined });
209209
const [pathValidationPending, setPathValidationPending] = React.useState(false);
210210
const validationRequestData = React.useRef<RequestMetaData>({ requestId: undefined });
211-
const errorMarkers = React.useRef<any[]>([])
211+
const errorMarkers = React.useRef<any[]>([]);
212212
const [validationResponse, setValidationResponse] = useState<CodeAutocompleteFieldValidationResult | undefined>(
213213
undefined
214214
);
@@ -300,26 +300,26 @@ const AutoSuggestion = ({
300300
const parseError = validationResponse?.parseError;
301301
if (cm) {
302302
const clearCurrentErrorMarker = () => {
303-
if(errorMarkers.current.length) {
303+
if (errorMarkers.current.length) {
304304
const [from, to] = errorMarkers.current;
305-
removeMarkFromText({ view: cm, from, to })
306-
errorMarkers.current = []
305+
removeMarkFromText({ view: cm, from, to });
306+
errorMarkers.current = [];
307307
}
308-
}
308+
};
309309
if (parseError) {
310310
const { message, start, end } = parseError;
311311
const { toOffset, fromOffset } = getOffsetRange(cm, start, end);
312-
clearCurrentErrorMarker()
313-
const {from, to} = markText({
312+
clearCurrentErrorMarker();
313+
const { from, to } = markText({
314314
view: cm,
315315
from: fromOffset,
316316
to: toOffset,
317317
className: `${eccgui}-autosuggestion__text--highlighted-error`,
318318
title: message,
319319
});
320-
errorMarkers.current = [from, to]
320+
errorMarkers.current = [from, to];
321321
} else {
322-
clearCurrentErrorMarker()
322+
clearCurrentErrorMarker();
323323
}
324324
}
325325

@@ -448,13 +448,13 @@ const AutoSuggestion = ({
448448
[asyncHandleEditorInputChange, autoCompletionRequestDelay]
449449
);
450450

451-
const handleChange = React.useMemo( () => {
451+
const handleChange = React.useMemo(() => {
452452
return (val: string) => {
453453
value.current = val;
454454
checkValuePathValidity.cancel();
455455
checkValuePathValidity(value.current);
456456
onChange(val);
457-
}
457+
};
458458
}, [onChange, checkValuePathValidity]);
459459

460460
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+
));

0 commit comments

Comments
 (0)