@elyra/canvas 13.30.0 → 13.31.0
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/dist/canvas-controller-5714c16e.js +2 -0
- package/dist/canvas-controller-5714c16e.js.map +1 -0
- package/dist/canvas-controller-fb3341f8.js +2 -0
- package/dist/canvas-controller-fb3341f8.js.map +1 -0
- package/dist/common-canvas-cb2af30e.js +2 -0
- package/dist/common-canvas-cb2af30e.js.map +1 -0
- package/dist/common-canvas-fed3a116.js +2 -0
- package/dist/common-canvas-fed3a116.js.map +1 -0
- package/dist/{common-canvas-utils-bbe543ed.js → common-canvas-utils-04c7ddd2.js} +1 -1
- package/dist/{common-canvas-utils-bbe543ed.js.map → common-canvas-utils-04c7ddd2.js.map} +1 -1
- package/dist/{common-canvas-utils-a489e236.js → common-canvas-utils-26fdf006.js} +1 -1
- package/dist/{common-canvas-utils-a489e236.js.map → common-canvas-utils-26fdf006.js.map} +1 -1
- package/dist/common-canvas.es.js +1 -1
- package/dist/common-canvas.js +1 -1
- package/dist/common-properties-6709d67d.js +2 -0
- package/dist/common-properties-6709d67d.js.map +1 -0
- package/dist/common-properties-9ea710be.js +2 -0
- package/dist/common-properties-9ea710be.js.map +1 -0
- package/dist/{context-menu-wrapper-ea061c95.js → context-menu-wrapper-c6dea37b.js} +2 -2
- package/dist/{context-menu-wrapper-ea061c95.js.map → context-menu-wrapper-c6dea37b.js.map} +1 -1
- package/dist/{context-menu-wrapper-7caefd31.js → context-menu-wrapper-ff90de76.js} +2 -2
- package/dist/{context-menu-wrapper-7caefd31.js.map → context-menu-wrapper-ff90de76.js.map} +1 -1
- package/dist/keyboard-utils-485bef78.js +2 -0
- package/dist/keyboard-utils-485bef78.js.map +1 -0
- package/dist/keyboard-utils-f7c4ec40.js +2 -0
- package/dist/keyboard-utils-f7c4ec40.js.map +1 -0
- package/dist/lib/canvas-controller.es.js +1 -1
- package/dist/lib/canvas-controller.js +1 -1
- package/dist/lib/canvas.es.js +1 -1
- package/dist/lib/canvas.js +1 -1
- package/dist/lib/context-menu.es.js +1 -1
- package/dist/lib/context-menu.js +1 -1
- package/dist/lib/properties.es.js +1 -1
- package/dist/lib/properties.js +1 -1
- package/dist/{toolbar-4ce5b537.js → toolbar-1db25a07.js} +2 -2
- package/dist/{toolbar-4ce5b537.js.map → toolbar-1db25a07.js.map} +1 -1
- package/dist/{toolbar-40d93a80.js → toolbar-4c42861f.js} +2 -2
- package/dist/{toolbar-40d93a80.js.map → toolbar-4c42861f.js.map} +1 -1
- package/package.json +4 -3
- package/src/command-actions/createAutoNodeAction.js +0 -7
- package/src/common-canvas/canvas-controller.js +28 -34
- package/src/common-canvas/cc-bottom-panel.jsx +21 -26
- package/src/common-canvas/cc-panels.jsx +16 -5
- package/src/common-canvas/cc-right-flyout.jsx +17 -33
- package/src/common-canvas/common-canvas-utils.js +6 -6
- package/src/common-canvas/keyboard-utils.js +3 -2
- package/src/common-canvas/svg-canvas-d3.js +4 -4
- package/src/common-canvas/svg-canvas-renderer.js +21 -7
- package/src/common-canvas/svg-canvas-utils-drag-objects.js +41 -7
- package/src/common-canvas/svg-canvas-utils-zoom.js +23 -5
- package/src/common-properties/components/editor-form/editor-form.jsx +2 -0
- package/src/common-properties/components/wide-flyout/wide-flyout.jsx +85 -5
- package/src/common-properties/controls/datepicker/datepicker.jsx +1 -0
- package/src/common-properties/controls/dropdown/dropdown.jsx +17 -11
- package/src/common-properties/form/ControlInfo.js +1 -1
- package/src/common-properties/panels/tearsheet/tearsheet.jsx +2 -1
- package/src/object-model/layout-dimensions.js +6 -0
- package/stats.html +1 -1
- package/types/canvas-controller.ts +18 -4
- package/types/common-canvas.ts +5 -0
- package/types/common-properties.ts +1 -1
- package/dist/canvas-controller-5b727491.js +0 -2
- package/dist/canvas-controller-5b727491.js.map +0 -1
- package/dist/canvas-controller-f1489f81.js +0 -2
- package/dist/canvas-controller-f1489f81.js.map +0 -1
- package/dist/common-canvas-4807ed78.js +0 -2
- package/dist/common-canvas-4807ed78.js.map +0 -1
- package/dist/common-canvas-a41d6dc9.js +0 -2
- package/dist/common-canvas-a41d6dc9.js.map +0 -1
- package/dist/common-properties-75f30ccf.js +0 -2
- package/dist/common-properties-75f30ccf.js.map +0 -1
- package/dist/common-properties-e2a321a6.js +0 -2
- package/dist/common-properties-e2a321a6.js.map +0 -1
- package/dist/keyboard-utils-232a10e1.js +0 -2
- package/dist/keyboard-utils-232a10e1.js.map +0 -1
- package/dist/keyboard-utils-ce49412d.js +0 -2
- package/dist/keyboard-utils-ce49412d.js.map +0 -1
|
@@ -657,9 +657,19 @@ export default class SVGCanvasUtilsZoom {
|
|
|
657
657
|
newZoomTransform.y !== this.zoomTransform.y;
|
|
658
658
|
}
|
|
659
659
|
|
|
660
|
-
// Zooms the canvas to fit in the current viewport.
|
|
661
|
-
zoomToFit() {
|
|
660
|
+
// Zooms all the canvas objects to fit in the current viewport.
|
|
661
|
+
zoomToFit(animateTime) {
|
|
662
662
|
const canvasDimensions = this.getCanvasDimensionsWithPadding();
|
|
663
|
+
const zoom = this.getZoomToFit(canvasDimensions);
|
|
664
|
+
if (zoom) {
|
|
665
|
+
this.zoomCanvasInvokeZoomBehavior(zoom, animateTime);
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
// Returns a zoom object that can be used to zoom canvas objects (nodes,
|
|
670
|
+
// comments and/or detached links), that occupy the canvasDimensions,
|
|
671
|
+
// to fit in the current viewport.
|
|
672
|
+
getZoomToFit(canvasDimensions) {
|
|
663
673
|
const viewPortDimensions = this.getViewportDimensions();
|
|
664
674
|
|
|
665
675
|
if (canvasDimensions) {
|
|
@@ -673,8 +683,9 @@ export default class SVGCanvasUtilsZoom {
|
|
|
673
683
|
x -= newScale * canvasDimensions.left;
|
|
674
684
|
y -= newScale * canvasDimensions.top;
|
|
675
685
|
|
|
676
|
-
|
|
686
|
+
return { x: x, y: y, k: newScale };
|
|
677
687
|
}
|
|
688
|
+
return null;
|
|
678
689
|
}
|
|
679
690
|
|
|
680
691
|
// Returns a zoom object that will, if applied to the canvas, zoom the objects
|
|
@@ -689,10 +700,17 @@ export default class SVGCanvasUtilsZoom {
|
|
|
689
700
|
if (nodes.length > 0 || comments.length > 0 || links.length > 0) {
|
|
690
701
|
const canvasDimensions = CanvasUtils.getCanvasDimensions(nodes, comments, links, 0, 0, true);
|
|
691
702
|
const canv = this.convertRectAdjustedForScaleWithPadding(canvasDimensions, 1, 30);
|
|
692
|
-
const xPosInt = parseInt(xPos, 10);
|
|
693
|
-
const yPosInt = typeof yPos === "undefined" ? xPosInt : parseInt(yPos, 10);
|
|
694
703
|
|
|
695
704
|
if (canv) {
|
|
705
|
+
// If the bounding rectangle (canv) doesn't completely fit in the viewport
|
|
706
|
+
// we do a zoom to fit to bring the requested objects into view.
|
|
707
|
+
if (canv.width > transformedSVGRect.width || canv.height > transformedSVGRect.height) {
|
|
708
|
+
return this.getZoomToFit(canv);
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
const xPosInt = parseInt(xPos, 10);
|
|
712
|
+
const yPosInt = typeof yPos === "undefined" ? xPosInt : parseInt(yPos, 10);
|
|
713
|
+
|
|
696
714
|
let xOffset;
|
|
697
715
|
let yOffset;
|
|
698
716
|
|
|
@@ -531,6 +531,7 @@ class EditorForm extends React.Component {
|
|
|
531
531
|
<TearSheet
|
|
532
532
|
open={this.props.controller.getActiveTearsheet() !== null}
|
|
533
533
|
onCloseCallback={onCloseCallback}
|
|
534
|
+
cancelHandler={onCloseCallback}
|
|
534
535
|
key={panel.id}
|
|
535
536
|
tearsheet={this.visibleTearsheet}
|
|
536
537
|
/>
|
|
@@ -683,6 +684,7 @@ class EditorForm extends React.Component {
|
|
|
683
684
|
stackedTearsheet = (<TearSheet
|
|
684
685
|
open
|
|
685
686
|
stacked
|
|
687
|
+
cancelHandler={this.closeFieldPicker}
|
|
686
688
|
tearsheet={{
|
|
687
689
|
title: title,
|
|
688
690
|
content: this.fieldPicker()
|
|
@@ -24,23 +24,65 @@ import { Portal } from "react-portal";
|
|
|
24
24
|
export default class WideFlyout extends Component {
|
|
25
25
|
constructor(props) {
|
|
26
26
|
super(props);
|
|
27
|
+
this.modalRef = React.createRef();
|
|
27
28
|
this.state = {
|
|
28
29
|
style: {
|
|
29
30
|
height: 0
|
|
30
31
|
}
|
|
31
32
|
};
|
|
32
33
|
this.updateDimensions = this.updateDimensions.bind(this);
|
|
34
|
+
this.handleTabKey = this.handleTabKey.bind(this);
|
|
33
35
|
}
|
|
34
36
|
|
|
35
37
|
componentDidMount() {
|
|
36
38
|
this.updateDimensions();
|
|
37
39
|
window.addEventListener("resize", this.updateDimensions);
|
|
40
|
+
document.addEventListener("keydown", this.handleTabKey);
|
|
41
|
+
this.focusOnFirstFocusable(); // Set initial focus inside the modal.
|
|
42
|
+
}
|
|
43
|
+
componentDidUpdate(prevProps) {
|
|
44
|
+
// If modal is still open, and new item added.
|
|
45
|
+
const modal = this.getActiveModal();
|
|
46
|
+
if (!prevProps.show && this.props.show && modal) {
|
|
47
|
+
// If focus is outside modal, move it to first focusable
|
|
48
|
+
this.focusOnFirstFocusable();
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
if (this.props.show && modal) {
|
|
52
|
+
const active = document.activeElement;
|
|
53
|
+
// Restore focus if lost due to modal content changes like typing or adding new fields
|
|
54
|
+
if (active === document.body || !modal.contains(active)) {
|
|
55
|
+
this.focusOnFirstFocusable();
|
|
56
|
+
}
|
|
57
|
+
}
|
|
38
58
|
}
|
|
39
|
-
|
|
40
59
|
componentWillUnmount() {
|
|
41
60
|
window.removeEventListener("resize", this.updateDimensions);
|
|
61
|
+
document.removeEventListener("keydown", this.handleTabKey);
|
|
62
|
+
}
|
|
63
|
+
// Returns an array of focusable elements inside the modal.
|
|
64
|
+
getFocusables() {
|
|
65
|
+
const modal = this.getActiveModal();
|
|
66
|
+
if (!modal) {
|
|
67
|
+
return [];
|
|
68
|
+
}
|
|
69
|
+
return Array.from(
|
|
70
|
+
modal.querySelectorAll(
|
|
71
|
+
"button, a[href], input, select, textarea, [tabindex]:not([tabindex='-1'])"
|
|
72
|
+
)).filter((el) => el.offsetParent !== null); // Filter out hidden/disabled elements.
|
|
73
|
+
}
|
|
74
|
+
// Focus on the first focusable element once modal opens.
|
|
75
|
+
getActiveModal() {
|
|
76
|
+
const modals = Array.from(document.querySelectorAll("div[role='dialog'].properties-wf-content.show"));
|
|
77
|
+
// Pick the last one — it's the top-most modal (deepest in DOM)
|
|
78
|
+
return modals.length > 0 ? modals[modals.length - 1] : null;
|
|
79
|
+
}
|
|
80
|
+
focusOnFirstFocusable() {
|
|
81
|
+
const focusables = this.getFocusables();
|
|
82
|
+
if (focusables.length > 0) {
|
|
83
|
+
focusables[0].focus();
|
|
84
|
+
}
|
|
42
85
|
}
|
|
43
|
-
|
|
44
86
|
updateDimensions() {
|
|
45
87
|
if (this.wideFlyout) {
|
|
46
88
|
// used to find correct parent
|
|
@@ -66,6 +108,39 @@ export default class WideFlyout extends Component {
|
|
|
66
108
|
}
|
|
67
109
|
return null;
|
|
68
110
|
}
|
|
111
|
+
// Handles focus trap inside the modal when using Tab or Shift+tab key.
|
|
112
|
+
handleTabKey(e) {
|
|
113
|
+
if (e.key !== "Tab") {
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
const modal = this.getActiveModal();
|
|
117
|
+
if (!modal || !this.props.show) {
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
const focusables = this.getFocusables();
|
|
121
|
+
if (focusables.length === 0) {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
const first = focusables[0];
|
|
125
|
+
const last = focusables[focusables.length - 1];
|
|
126
|
+
const active = document.activeElement;
|
|
127
|
+
// If focus is outside modal or on <body>,Then bring back to the first element inside modal.
|
|
128
|
+
if (this.props.show && (!modal.contains(active) || active === document.body)) {
|
|
129
|
+
e.preventDefault();
|
|
130
|
+
// If "Shift+Tab" then focus should be on last element inside the modal else first.
|
|
131
|
+
(e.shiftKey ? last : first).focus();
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
if (e.shiftKey) {
|
|
135
|
+
if (active === first) {
|
|
136
|
+
e.preventDefault();
|
|
137
|
+
last.focus();
|
|
138
|
+
}
|
|
139
|
+
} else if (active === last) {
|
|
140
|
+
e.preventDefault();
|
|
141
|
+
first.focus();
|
|
142
|
+
}
|
|
143
|
+
}
|
|
69
144
|
|
|
70
145
|
render() {
|
|
71
146
|
const overlay = (<div className={classNames("properties-wf-overlay", { "show": this.props.show })} />);
|
|
@@ -87,10 +162,15 @@ export default class WideFlyout extends Component {
|
|
|
87
162
|
children = (<div className="properties-wf-children"> {this.props.children} </div>);
|
|
88
163
|
}
|
|
89
164
|
return (
|
|
90
|
-
<div className="properties-wf-modal" ref={
|
|
165
|
+
<div className="properties-wf-modal" ref={(ref) => (this.wideFlyout = ref)}>
|
|
91
166
|
<Portal node={this.commonPropertiesParent}>
|
|
92
|
-
{
|
|
93
|
-
<div
|
|
167
|
+
{overlay}
|
|
168
|
+
<div
|
|
169
|
+
ref={this.modalRef}
|
|
170
|
+
role="dialog"
|
|
171
|
+
className={classNames("properties-wf-content", { "show": this.props.show, "properties-light-disabled": !this.props.light })}
|
|
172
|
+
style={this.state.style}
|
|
173
|
+
>
|
|
94
174
|
{title}
|
|
95
175
|
{children}
|
|
96
176
|
{buttons}
|
|
@@ -193,18 +193,24 @@ class DropDown extends React.Component {
|
|
|
193
193
|
this.props.controller.updatePropertyValue(this.props.propertyId, value);
|
|
194
194
|
}
|
|
195
195
|
|
|
196
|
-
|
|
197
|
-
handleOnInputChange(evt) {
|
|
196
|
+
|
|
197
|
+
handleOnInputChange(evt, options) {
|
|
198
198
|
const currentValue = this.props.controller.getPropertyValue(this.props.propertyId);
|
|
199
199
|
|
|
200
200
|
// Don't update property value during initial render
|
|
201
201
|
if ((typeof currentValue === "undefined" || currentValue === null) && evt === "") {
|
|
202
202
|
return;
|
|
203
203
|
}
|
|
204
|
-
|
|
205
|
-
if (
|
|
206
|
-
|
|
207
|
-
|
|
204
|
+
const value = evt;
|
|
205
|
+
if (this.props.control.customValueAllowed) {
|
|
206
|
+
if (evt !== null && evt !== currentValue) {
|
|
207
|
+
this.props.controller.updatePropertyValue(this.props.propertyId, value);
|
|
208
|
+
}
|
|
209
|
+
} else { // check and update only if input is present in options when customValueAllowed=false
|
|
210
|
+
const isValidInput = options.some((opt) => opt.label === evt);
|
|
211
|
+
if (isValidInput && evt !== null && evt !== currentValue) {
|
|
212
|
+
this.props.controller.updatePropertyValue(this.props.propertyId, value);
|
|
213
|
+
}
|
|
208
214
|
}
|
|
209
215
|
}
|
|
210
216
|
|
|
@@ -278,7 +284,7 @@ class DropDown extends React.Component {
|
|
|
278
284
|
{ options }
|
|
279
285
|
</Select>
|
|
280
286
|
);
|
|
281
|
-
} else if (this.props.control.customValueAllowed) { // combobox dropdown not allowed in tables
|
|
287
|
+
} else if (this.props.control.customValueAllowed || this.props.control.shouldFilterItem) { // combobox dropdown not allowed in tables
|
|
282
288
|
const shouldFilterItem = this.props.control.shouldFilterItem === true ? { shouldFilterItem: this.filterItems } : {};
|
|
283
289
|
dropdownComponent = (
|
|
284
290
|
<ComboBox
|
|
@@ -286,15 +292,15 @@ class DropDown extends React.Component {
|
|
|
286
292
|
aria-label={this.props.control.label ? this.props.control.label.text : ""}
|
|
287
293
|
id={`${ControlUtils.getDataId(this.props.propertyId)}-dropdown`}
|
|
288
294
|
disabled={this.props.state === STATES.DISABLED || this.disableEmptyListDropdown}
|
|
289
|
-
placeholder={dropDown.selectedOption
|
|
290
|
-
selectedItem={dropDown.selectedOption
|
|
295
|
+
placeholder={dropDown.selectedOption?.label}
|
|
296
|
+
selectedItem={dropDown.selectedOption?.label}
|
|
291
297
|
items={dropDown.options}
|
|
292
298
|
onChange={this.handleComboOnChange}
|
|
293
|
-
onInputChange={this.handleOnInputChange}
|
|
299
|
+
onInputChange={(evt) => this.handleOnInputChange(evt, dropDown.options)}
|
|
294
300
|
translateWithId={(id) => listBoxMenuIconTranslationIds[id]}
|
|
295
301
|
titleText={this.props.controlItem}
|
|
296
302
|
helperText={this.props.control.helperText}
|
|
297
|
-
allowCustomValue
|
|
303
|
+
allowCustomValue={this.props.control.customValueAllowed}
|
|
298
304
|
{...shouldFilterItem}
|
|
299
305
|
/>
|
|
300
306
|
);
|
|
@@ -172,7 +172,7 @@ export class Control {
|
|
|
172
172
|
if (typeof settings.visible === "boolean") {
|
|
173
173
|
this.visible = settings.visible;
|
|
174
174
|
}
|
|
175
|
-
if (typeof settings.width === "number") {
|
|
175
|
+
if (typeof settings.width === "number" || (!isNaN(parseInt(settings.width, 10)) && settings.width?.endsWith("px"))) {
|
|
176
176
|
this.width = settings.width;
|
|
177
177
|
}
|
|
178
178
|
if (settings.editStyle) {
|
|
@@ -52,6 +52,7 @@ class TearSheet extends Component {
|
|
|
52
52
|
size="lg"
|
|
53
53
|
aria-label={formatMessage(this.props.intl, MESSAGE_KEYS.PROPERTIES_LABEL, { label: title })}
|
|
54
54
|
preventCloseOnClickOutside
|
|
55
|
+
onClose={this.props.cancelHandler} // for case where user closes the modal by pressing ESC
|
|
55
56
|
>
|
|
56
57
|
{title === null
|
|
57
58
|
? null
|
|
@@ -93,7 +94,7 @@ TearSheet.propTypes = {
|
|
|
93
94
|
applyLabel: PropTypes.string, // Required if showPropertiesButtons is true
|
|
94
95
|
rejectLabel: PropTypes.string, // Required if showPropertiesButtons is true
|
|
95
96
|
okHandler: PropTypes.func, // Required if showPropertiesButtons is true
|
|
96
|
-
cancelHandler: PropTypes.func,
|
|
97
|
+
cancelHandler: PropTypes.func.isRequired,
|
|
97
98
|
applyOnBlur: PropTypes.bool.isRequired,
|
|
98
99
|
intl: PropTypes.object.isRequired,
|
|
99
100
|
controller: PropTypes.object.isRequired,
|
|
@@ -121,6 +121,9 @@ const horizontalDefaultLayout = {
|
|
|
121
121
|
// Allows the user to resize the node.
|
|
122
122
|
nodeResizable: false,
|
|
123
123
|
|
|
124
|
+
// Allows the user to move the node. Can be: true or false.
|
|
125
|
+
nodeMovable: true,
|
|
126
|
+
|
|
124
127
|
// The size of the node sizing area that extends around the node, over
|
|
125
128
|
// which the mouse pointer will change to the sizing arrows.
|
|
126
129
|
nodeSizingArea: 10,
|
|
@@ -600,6 +603,9 @@ const verticalDefaultLayout = {
|
|
|
600
603
|
// Allows the user to resize the node.
|
|
601
604
|
nodeResizable: false,
|
|
602
605
|
|
|
606
|
+
// Allows the user to move the node. Can be: true or false.
|
|
607
|
+
nodeMovable: true,
|
|
608
|
+
|
|
603
609
|
// The size of the node sizing area that extends around the node, over
|
|
604
610
|
// which the mouse pointer will change to the sizing arrows.
|
|
605
611
|
nodeSizingArea: 10,
|