@elyra/canvas 12.42.0 → 12.43.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-constants-13b58448.js → canvas-constants-acb99f64.js} +2 -2
- package/dist/{canvas-constants-13b58448.js.map → canvas-constants-acb99f64.js.map} +1 -1
- package/dist/{canvas-controller-cb1d7420.js → canvas-controller-6726b9ac.js} +2 -2
- package/dist/{canvas-controller-a53943e4.js.map → canvas-controller-6726b9ac.js.map} +1 -1
- package/dist/{canvas-controller-a53943e4.js → canvas-controller-6c6bc68f.js} +2 -2
- package/dist/{canvas-controller-cb1d7420.js.map → canvas-controller-6c6bc68f.js.map} +1 -1
- package/dist/common-canvas-9374ef35.js +2 -0
- package/dist/common-canvas-9374ef35.js.map +1 -0
- package/dist/common-canvas-a6435bdb.js +2 -0
- package/dist/common-canvas-a6435bdb.js.map +1 -0
- package/dist/common-canvas.es.js +1 -1
- package/dist/common-canvas.es.js.map +1 -1
- package/dist/common-canvas.js +1 -1
- package/dist/common-canvas.js.map +1 -1
- package/dist/common-properties-08707efe.js +2 -0
- package/dist/common-properties-08707efe.js.map +1 -0
- package/dist/common-properties-acd55e94.js +2 -0
- package/dist/common-properties-acd55e94.js.map +1 -0
- package/dist/context-menu-wrapper-271eb2df.js +2 -0
- package/dist/context-menu-wrapper-271eb2df.js.map +1 -0
- package/dist/context-menu-wrapper-e4a7ab4d.js +2 -0
- package/dist/context-menu-wrapper-e4a7ab4d.js.map +1 -0
- package/dist/{datarecord-metadata-v3-schema-98ec66e9.js → datarecord-metadata-v3-schema-03427296.js} +2 -2
- package/dist/{datarecord-metadata-v3-schema-98ec66e9.js.map → datarecord-metadata-v3-schema-03427296.js.map} +1 -1
- package/dist/{flexible-table-7c7de0f9.js → flexible-table-107ca2fd.js} +1 -1
- package/dist/{flexible-table-7c7de0f9.js.map → flexible-table-107ca2fd.js.map} +1 -1
- package/dist/{flexible-table-35e9922a.js → flexible-table-5cc1ad6b.js} +1 -1
- package/dist/{flexible-table-35e9922a.js.map → flexible-table-5cc1ad6b.js.map} +1 -1
- package/dist/{icon-9edff40c.js → icon-2caf035c.js} +2 -2
- package/dist/{icon-9edff40c.js.map → icon-2caf035c.js.map} +1 -1
- package/dist/{index-94fec521.js → index-5dac3da8.js} +2 -2
- package/dist/{index-94fec521.js.map → index-5dac3da8.js.map} +1 -1
- package/dist/{index-e2f8a935.js → index-fee06179.js} +2 -2
- package/dist/{index-e2f8a935.js.map → index-fee06179.js.map} +1 -1
- 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/clem.es.js +2 -0
- package/dist/lib/properties/clem.es.js.map +1 -0
- package/dist/lib/properties/clem.js +2 -0
- package/dist/lib/properties/clem.js.map +1 -0
- package/dist/lib/properties/field-picker.es.js +1 -1
- package/dist/lib/properties/field-picker.js +1 -1
- package/dist/lib/properties/flexible-table.es.js +1 -1
- package/dist/lib/properties/flexible-table.js +1 -1
- package/dist/lib/properties/getPythonHints.es.js +2 -0
- package/dist/lib/properties/getPythonHints.es.js.map +1 -0
- package/dist/lib/properties/getPythonHints.js +2 -0
- package/dist/lib/properties/getPythonHints.js.map +1 -0
- package/dist/lib/properties.es.js +1 -1
- package/dist/lib/properties.js +1 -1
- package/dist/lib/tooltip.es.js +1 -1
- package/dist/lib/tooltip.es.js.map +1 -1
- package/dist/lib/tooltip.js +1 -1
- package/dist/lib/tooltip.js.map +1 -1
- package/dist/styles/common-canvas.min.css +1 -1
- package/dist/styles/common-canvas.min.css.map +1 -1
- package/dist/toolbar-ccc1d600.js +2 -0
- package/dist/toolbar-ccc1d600.js.map +1 -0
- package/dist/toolbar-e4445bf8.js +2 -0
- package/dist/toolbar-e4445bf8.js.map +1 -0
- package/package.json +3 -3
- package/rollup.config.js +2 -0
- package/src/color-picker/color-picker.jsx +5 -1
- package/src/common-canvas/canvas-controller.js +38 -0
- package/src/common-canvas/cc-central-items.jsx +0 -4
- package/src/common-canvas/cc-toolbar.jsx +26 -9
- package/src/common-canvas/common-canvas.scss +3 -3
- package/src/common-canvas/svg-canvas-d3.scss +3 -2
- package/src/common-canvas/svg-canvas-renderer.js +44 -21
- package/src/common-properties/components/field-picker/field-picker.jsx +4 -0
- package/src/common-properties/controls/checkbox/checkbox.scss +0 -1
- package/src/common-properties/controls/expression/expression.jsx +3 -5
- package/src/common-properties/controls/expression/languages/python-hint.js +18 -30
- package/src/common-properties/controls/expression/languages/r-hint.js +16 -8
- package/src/common-properties/index.js +4 -2
- package/src/index.js +2 -2
- package/src/notification-panel/notification-panel.jsx +82 -56
- package/src/notification-panel/notification-panel.scss +42 -40
- package/src/object-model/object-model.js +19 -5
- package/src/object-model/redux/reducers/canvasinfo.js +7 -11
- package/src/object-model/redux/reducers/canvastoolbar.js +5 -6
- package/src/palette/palette-dialog-topbar.jsx +27 -38
- package/src/palette/palette-flyout-content-category.jsx +25 -6
- package/src/palette/palette.scss +8 -40
- package/src/toolbar/index.js +18 -0
- package/src/toolbar/toolbar-action-item.jsx +40 -10
- package/src/toolbar/toolbar-button-item.jsx +46 -19
- package/src/toolbar/toolbar-divider-item.jsx +1 -1
- package/src/toolbar/toolbar-overflow-item.jsx +4 -2
- package/src/toolbar/toolbar-sub-menu-item.jsx +6 -5
- package/src/toolbar/toolbar-sub-menu.jsx +4 -6
- package/src/toolbar/toolbar-sub-panel.jsx +31 -18
- package/src/toolbar/toolbar-sub-utils.js +21 -12
- package/src/toolbar/toolbar.jsx +79 -25
- package/src/toolbar/toolbar.scss +47 -47
- package/src/tooltip/tooltip.jsx +56 -10
- package/stats.html +1 -1
- package/assets/images/palette/close_32.svg +0 -1
- package/assets/images/palette/palette_close.svg +0 -4
- package/assets/images/palette/palette_grid_deselected.svg +0 -2
- package/assets/images/palette/palette_grid_hover.svg +0 -2
- package/assets/images/palette/palette_grid_selected.svg +0 -2
- package/assets/images/palette/palette_list_deselected.svg +0 -1
- package/assets/images/palette/palette_list_hover.svg +0 -1
- package/assets/images/palette/palette_list_selected.svg +0 -1
- package/assets/images/palette/palette_open.svg +0 -4
- package/assets/images/zoom_to_fit.svg +0 -8
- package/dist/common-canvas-42027a3f.js +0 -2
- package/dist/common-canvas-42027a3f.js.map +0 -1
- package/dist/common-canvas-f758ff42.js +0 -2
- package/dist/common-canvas-f758ff42.js.map +0 -1
- package/dist/common-properties-2e1b7ec7.js +0 -2
- package/dist/common-properties-2e1b7ec7.js.map +0 -1
- package/dist/common-properties-5e8870e3.js +0 -2
- package/dist/common-properties-5e8870e3.js.map +0 -1
- package/dist/context-menu-wrapper-49f9a1af.js +0 -2
- package/dist/context-menu-wrapper-49f9a1af.js.map +0 -1
- package/dist/context-menu-wrapper-5d6a399f.js +0 -2
- package/dist/context-menu-wrapper-5d6a399f.js.map +0 -1
- package/dist/toolbar-6acda0a2.js +0 -2
- package/dist/toolbar-6acda0a2.js.map +0 -1
- package/dist/toolbar-d5647da2.js +0 -2
- package/dist/toolbar-d5647da2.js.map +0 -1
- package/src/palette/palette-dialog-topbar-three-way-icon.jsx +0 -82
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* Copyright 2017-
|
|
2
|
+
* Copyright 2017-2024 Elyra Authors
|
|
3
3
|
*
|
|
4
4
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
5
|
* you may not use this file except in compliance with the License.
|
|
@@ -21,9 +21,6 @@ import Tooltip from "../tooltip/tooltip.jsx";
|
|
|
21
21
|
import ArrangeHorizontally from "./../../assets/images/arrange_horizontally.svg";
|
|
22
22
|
import ArrangeVertically from "./../../assets/images/arrange_vertically.svg";
|
|
23
23
|
import ToggleNotificationPanel from "./../../assets/images/notification_counter_icon.svg";
|
|
24
|
-
import PaletteClose from "./../../assets/images/palette/palette_close.svg";
|
|
25
|
-
import PaletteOpen from "./../../assets/images/palette/palette_open.svg";
|
|
26
|
-
import ZoomToFit from "./../../assets/images/zoom_to_fit.svg";
|
|
27
24
|
|
|
28
25
|
import { Button } from "carbon-components-react";
|
|
29
26
|
import SVG from "react-inlinesvg";
|
|
@@ -31,7 +28,8 @@ import classNames from "classnames";
|
|
|
31
28
|
import { StopFilledAlt16, Play16, Undo16, Redo16, Chat16, ChatOff16, Result16,
|
|
32
29
|
Cut16, Copy16, Paste16, Edit16, ColorPalette16, Maximize16, Minimize16,
|
|
33
30
|
Launch16, AddComment16, TrashCan16, ZoomIn16, ZoomOut16,
|
|
34
|
-
ChevronRight16, ChevronDown16, ChevronUp16
|
|
31
|
+
ChevronRight16, ChevronDown16, ChevronUp16,
|
|
32
|
+
CenterToFit16, OpenPanelFilledLeft16 } from "@carbon/icons-react";
|
|
35
33
|
import { TOOLBAR_STOP, TOOLBAR_RUN, TOOLBAR_UNDO, TOOLBAR_REDO,
|
|
36
34
|
TOOLBAR_CUT, TOOLBAR_COPY, TOOLBAR_PASTE, TOOLBAR_CLIPBOARD,
|
|
37
35
|
TOOLBAR_CREATE_COMMENT, TOOLBAR_CREATE_AUTO_COMMENT, TOOLBAR_COLOR_BACKGROUND,
|
|
@@ -54,6 +52,14 @@ class ToolbarButtonItem extends React.Component {
|
|
|
54
52
|
componentDidUpdate() {
|
|
55
53
|
if (this.props.isFocusInToolbar &&
|
|
56
54
|
this.props.buttonFocusAction === this.props.actionObj.action) {
|
|
55
|
+
// If a Jsx object was provided, the class of the component should have
|
|
56
|
+
// been set to toolbar-jsx-obj.
|
|
57
|
+
const jsxItem = this.buttonRef.current.querySelector(".toolbar-jsx-obj");
|
|
58
|
+
if (jsxItem) {
|
|
59
|
+
jsxItem.focus();
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
|
|
57
63
|
this.buttonRef.current.focus();
|
|
58
64
|
}
|
|
59
65
|
}
|
|
@@ -105,17 +111,18 @@ class ToolbarButtonItem extends React.Component {
|
|
|
105
111
|
return <ZoomIn16 disabled={disabled} />;
|
|
106
112
|
case (TOOLBAR_ZOOM_OUT):
|
|
107
113
|
return <ZoomOut16 disabled={disabled} />;
|
|
108
|
-
|
|
109
114
|
case (TOOLBAR_ZOOM_FIT):
|
|
110
|
-
return <
|
|
115
|
+
return <CenterToFit16 disabled={disabled} />;
|
|
116
|
+
case (TOOLBAR_OPEN_PALETTE):
|
|
117
|
+
return <OpenPanelFilledLeft16 disabled={disabled} />;
|
|
118
|
+
case (TOOLBAR_CLOSE_PALETTE):
|
|
119
|
+
return <OpenPanelFilledLeft16 disabled={disabled} />;
|
|
120
|
+
|
|
121
|
+
// Non-carbon icons
|
|
111
122
|
case (TOOLBAR_ARRANGE_HORIZONALLY):
|
|
112
123
|
return <SVG src={ArrangeHorizontally} disabled={disabled} />;
|
|
113
124
|
case (TOOLBAR_ARRANGE_VERTICALLY):
|
|
114
125
|
return <SVG src={ArrangeVertically} disabled={disabled} />;
|
|
115
|
-
case (TOOLBAR_OPEN_PALETTE):
|
|
116
|
-
return <SVG src={PaletteOpen} disabled={disabled} />;
|
|
117
|
-
case (TOOLBAR_CLOSE_PALETTE):
|
|
118
|
-
return <SVG src={PaletteClose} disabled={disabled} />;
|
|
119
126
|
case (TOOLBAR_TOGGLE_NOTIFICATION_PANEL):
|
|
120
127
|
return <SVG src={ToggleNotificationPanel} disabled={disabled} />;
|
|
121
128
|
|
|
@@ -169,7 +176,7 @@ class ToolbarButtonItem extends React.Component {
|
|
|
169
176
|
return null;
|
|
170
177
|
}
|
|
171
178
|
|
|
172
|
-
|
|
179
|
+
generateRegularItem(actionObj) {
|
|
173
180
|
let labelBefore = null;
|
|
174
181
|
let labelAfter = null;
|
|
175
182
|
|
|
@@ -264,6 +271,26 @@ class ToolbarButtonItem extends React.Component {
|
|
|
264
271
|
);
|
|
265
272
|
}
|
|
266
273
|
|
|
274
|
+
// Creates a <div> containing the JSX in the actionObj.jsx field, wrapped in a tooltip
|
|
275
|
+
// <div>, for display as an action item in the toolbar. The jsx field can be just
|
|
276
|
+
// regular JSX OR a function that returns JSX. If the application has provided a
|
|
277
|
+
// function we call it, passing in the tabIndex that the component in the JSX should
|
|
278
|
+
// use, based on whether it is focused or not.
|
|
279
|
+
generateJsxItem(actionObj) {
|
|
280
|
+
let content = null;
|
|
281
|
+
if (typeof actionObj.jsx === "function") {
|
|
282
|
+
const tabIndex = this.props.buttonFocusAction === actionObj.action ? 0 : -1;
|
|
283
|
+
content = actionObj.jsx(tabIndex);
|
|
284
|
+
} else {
|
|
285
|
+
content = actionObj.jsx;
|
|
286
|
+
}
|
|
287
|
+
const jsx = this.wrapInTooltip(content);
|
|
288
|
+
const div = (<div ref={this.buttonRef}>{jsx}</div>);
|
|
289
|
+
|
|
290
|
+
return div;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
|
|
267
294
|
wrapInTooltip(content) {
|
|
268
295
|
if (!this.props.isInMenu && (this.showLabelAsTip(this.props.actionObj) || this.props.actionObj.tooltip)) {
|
|
269
296
|
const tip = this.props.actionObj.tooltip ? this.props.actionObj.tooltip : this.props.actionObj.label;
|
|
@@ -296,13 +323,10 @@ class ToolbarButtonItem extends React.Component {
|
|
|
296
323
|
|
|
297
324
|
render() {
|
|
298
325
|
const actionObj = this.props.actionObj;
|
|
299
|
-
let divContent = null;
|
|
300
326
|
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
divContent = this.generateButton(actionObj);
|
|
305
|
-
}
|
|
327
|
+
const divContent = actionObj.jsx
|
|
328
|
+
? this.generateJsxItem(actionObj)
|
|
329
|
+
: this.generateRegularItem(actionObj);
|
|
306
330
|
|
|
307
331
|
return divContent;
|
|
308
332
|
}
|
|
@@ -333,7 +357,10 @@ ToolbarButtonItem.propTypes = {
|
|
|
333
357
|
subMenu: PropTypes.array,
|
|
334
358
|
subPanel: PropTypes.any,
|
|
335
359
|
subPanelData: PropTypes.object,
|
|
336
|
-
jsx: PropTypes.
|
|
360
|
+
jsx: PropTypes.oneOfType([
|
|
361
|
+
PropTypes.object,
|
|
362
|
+
PropTypes.func
|
|
363
|
+
]),
|
|
337
364
|
tooltip: PropTypes.oneOfType([
|
|
338
365
|
PropTypes.string,
|
|
339
366
|
PropTypes.object,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* Copyright 2017-
|
|
2
|
+
* Copyright 2017-2024 Elyra Authors
|
|
3
3
|
*
|
|
4
4
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
5
|
* you may not use this file except in compliance with the License.
|
|
@@ -89,6 +89,7 @@ class ToolbarOverflowItem extends React.Component {
|
|
|
89
89
|
|
|
90
90
|
} else {
|
|
91
91
|
document.addEventListener("click", this.clickOutside, false);
|
|
92
|
+
this.props.closeAnyOpenSubArea();
|
|
92
93
|
this.props.setOverflowIndex(this.props.index);
|
|
93
94
|
this.openSubMenu();
|
|
94
95
|
this.props.setToolbarFocusAction(this.props.action);
|
|
@@ -168,7 +169,8 @@ ToolbarOverflowItem.propTypes = {
|
|
|
168
169
|
containingDivId: PropTypes.string,
|
|
169
170
|
toolbarFocusAction: PropTypes.string,
|
|
170
171
|
setToolbarFocusAction: PropTypes.func,
|
|
171
|
-
isFocusInToolbar: PropTypes.bool
|
|
172
|
+
isFocusInToolbar: PropTypes.bool,
|
|
173
|
+
closeAnyOpenSubArea: PropTypes.func
|
|
172
174
|
};
|
|
173
175
|
|
|
174
176
|
export default ToolbarOverflowItem;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* Copyright 2017-
|
|
2
|
+
* Copyright 2017-2024 Elyra Authors
|
|
3
3
|
*
|
|
4
4
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
5
|
* you may not use this file except in compliance with the License.
|
|
@@ -62,9 +62,9 @@ class ToolbarSubMenuItem extends React.Component {
|
|
|
62
62
|
clickOutside(evt) {
|
|
63
63
|
if (this.state.subAreaDisplayed) {
|
|
64
64
|
const items = document.getElementsByClassName(this.generateActionName());
|
|
65
|
-
const isOver = items
|
|
65
|
+
const isOver = items?.length > 0 ? items[0].contains(evt.target) : false;
|
|
66
66
|
|
|
67
|
-
if (!isOver) {
|
|
67
|
+
if (!isOver && !this.props.actionObj.leaveSubAreaOpenOnClickOutside) {
|
|
68
68
|
this.closeSubArea();
|
|
69
69
|
}
|
|
70
70
|
}
|
|
@@ -93,14 +93,14 @@ class ToolbarSubMenuItem extends React.Component {
|
|
|
93
93
|
} else {
|
|
94
94
|
evt.stopPropagation();
|
|
95
95
|
if (this.props.isInCascadeMenu) {
|
|
96
|
-
this.props.closeParentSubArea();
|
|
96
|
+
this.props.closeParentSubArea(true); // true = close only if closeSubAreaOnClick is checked
|
|
97
97
|
this.props.setSubMenuFocus();
|
|
98
98
|
|
|
99
99
|
} else if (this.props.isInOverflowMenu) {
|
|
100
100
|
this.props.setSubMenuFocus(this.props.actionObj.action);
|
|
101
101
|
|
|
102
102
|
} else {
|
|
103
|
-
this.props.closeParentSubArea();
|
|
103
|
+
this.props.closeParentSubArea(true); // true = close only if closeSubAreaOnClick is checked
|
|
104
104
|
this.props.setToolbarFocusAction(); // Resets the toolbar focus action
|
|
105
105
|
}
|
|
106
106
|
this.props.toolbarActionHandler(this.props.actionObj.action, evt);
|
|
@@ -210,6 +210,7 @@ ToolbarSubMenuItem.propTypes = {
|
|
|
210
210
|
isSelected: PropTypes.bool,
|
|
211
211
|
kind: PropTypes.string,
|
|
212
212
|
closeSubAreaOnClick: PropTypes.bool,
|
|
213
|
+
leaveSubAreaOpenOnClickOutside: PropTypes.bool,
|
|
213
214
|
subMenu: PropTypes.array,
|
|
214
215
|
subPanel: PropTypes.any,
|
|
215
216
|
subPanelData: PropTypes.object,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* Copyright
|
|
2
|
+
* Copyright 2024 Elyra Authors
|
|
3
3
|
*
|
|
4
4
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
5
|
* you may not use this file except in compliance with the License.
|
|
@@ -35,8 +35,6 @@ class ToolbarSubMenu extends React.Component {
|
|
|
35
35
|
focusAction: "subarea"
|
|
36
36
|
};
|
|
37
37
|
|
|
38
|
-
this.areaRef = React.createRef();
|
|
39
|
-
|
|
40
38
|
this.onKeyDown = this.onKeyDown.bind(this);
|
|
41
39
|
this.setFocusAction = this.setFocusAction.bind(this);
|
|
42
40
|
this.setSubMenuFocus = this.setSubMenuFocus.bind(this);
|
|
@@ -143,7 +141,7 @@ class ToolbarSubMenu extends React.Component {
|
|
|
143
141
|
const focusableActions = [];
|
|
144
142
|
|
|
145
143
|
for (let i = 0; i < this.props.subMenuActions.length; i++) {
|
|
146
|
-
if (this.props.subMenuActions[i].enable) {
|
|
144
|
+
if (this.props.subMenuActions[i].enable || this.props.subMenuActions[i].jsx) {
|
|
147
145
|
focusableActions.push(this.props.subMenuActions[i]);
|
|
148
146
|
}
|
|
149
147
|
}
|
|
@@ -224,7 +222,7 @@ class ToolbarSubMenu extends React.Component {
|
|
|
224
222
|
this.subMenuItems = this.generateSubMenuItems();
|
|
225
223
|
|
|
226
224
|
return (
|
|
227
|
-
<div ref={this.areaRef} style={style} className={"toolbar-popover-list submenu"}
|
|
225
|
+
<div ref={(ref) => (this.areaRef = ref)} style={style} className={"toolbar-popover-list submenu"}
|
|
228
226
|
tabIndex={-1} onKeyDown={this.onKeyDown}
|
|
229
227
|
>
|
|
230
228
|
{this.subMenuItems}
|
|
@@ -242,7 +240,7 @@ ToolbarSubMenu.propTypes = {
|
|
|
242
240
|
closeSubArea: PropTypes.func,
|
|
243
241
|
setToolbarFocusAction: PropTypes.func,
|
|
244
242
|
setSubMenuFocus: PropTypes.func,
|
|
245
|
-
actionItemRect: PropTypes.object
|
|
243
|
+
actionItemRect: PropTypes.object,
|
|
246
244
|
expandDirection: PropTypes.string.isRequired,
|
|
247
245
|
containingDivId: PropTypes.string,
|
|
248
246
|
parentSelector: PropTypes.string,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* Copyright
|
|
2
|
+
* Copyright 2024 Elyra Authors
|
|
3
3
|
*
|
|
4
4
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
5
|
* you may not use this file except in compliance with the License.
|
|
@@ -20,46 +20,59 @@ import PropTypes from "prop-types";
|
|
|
20
20
|
import { adjustSubAreaPosition, generateSubAreaStyle } from "./toolbar-sub-utils.js";
|
|
21
21
|
|
|
22
22
|
const ESC_KEY = 27;
|
|
23
|
+
const LEFT_ARROW_KEY = 37;
|
|
24
|
+
const RIGHT_ARROW_KEY = 39;
|
|
25
|
+
|
|
23
26
|
|
|
24
27
|
class ToolbarSubPanel extends React.Component {
|
|
25
28
|
constructor(props) {
|
|
26
29
|
super(props);
|
|
27
30
|
|
|
28
|
-
this.areaRef = React.createRef();
|
|
29
|
-
|
|
30
|
-
this.onClick = this.onClick.bind(this);
|
|
31
31
|
this.onKeyDown = this.onKeyDown.bind(this);
|
|
32
|
+
this.closeSubPanel = this.closeSubPanel.bind(this);
|
|
32
33
|
}
|
|
33
34
|
|
|
34
35
|
componentDidMount() {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
this.props.containingDivId, this.props.expandDirection, this.props.actionItemRect);
|
|
38
|
-
}
|
|
36
|
+
adjustSubAreaPosition(this.areaRef,
|
|
37
|
+
this.props.containingDivId, this.props.expandDirection, this.props.actionItemRect);
|
|
39
38
|
}
|
|
40
39
|
|
|
41
|
-
|
|
42
|
-
this.
|
|
40
|
+
componentDidUpdate() {
|
|
41
|
+
adjustSubAreaPosition(this.areaRef,
|
|
42
|
+
this.props.containingDivId, this.props.expandDirection, this.props.actionItemRect);
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
onKeyDown(evt) {
|
|
46
46
|
if (evt.keyCode === ESC_KEY) {
|
|
47
47
|
this.props.closeSubArea();
|
|
48
48
|
evt.stopPropagation();
|
|
49
|
+
|
|
50
|
+
} else if (evt.keyCode === LEFT_ARROW_KEY || evt.keyCode === RIGHT_ARROW_KEY) {
|
|
51
|
+
evt.stopPropagation();
|
|
49
52
|
}
|
|
50
53
|
}
|
|
51
54
|
|
|
55
|
+
// If the user clicks the panel background, by default focus would go
|
|
56
|
+
// through to the toolbar and focus would be lost from this sub-panel.
|
|
57
|
+
// This method prevents any focus event going through to the toolbar.
|
|
58
|
+
onFocus(evt) {
|
|
59
|
+
evt.stopPropagation();
|
|
60
|
+
evt.preventDefault();
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
closeSubPanel(evt) {
|
|
64
|
+
this.props.closeSubArea(); // Don't pass a paremeter otherwise it will check closeSubAreaOnClick.
|
|
65
|
+
}
|
|
66
|
+
|
|
52
67
|
render() {
|
|
53
68
|
const style = generateSubAreaStyle(this.props.expandDirection, this.props.actionItemRect);
|
|
54
69
|
|
|
55
70
|
if (this.props.subPanel) {
|
|
56
|
-
const subPanel = typeof this.props.subPanel === "object"
|
|
57
|
-
? this.props.subPanel
|
|
58
|
-
: (<this.props.subPanel closeSubPanel={this.props.closeSubArea} subPanelData={this.props.subPanelData} />);
|
|
59
|
-
|
|
60
71
|
return (
|
|
61
|
-
<div ref={this.areaRef} style={style} className={"toolbar-popover-list subpanel"}
|
|
62
|
-
{
|
|
72
|
+
<div ref={(ref) => (this.areaRef = ref)} style={style} className={"toolbar-popover-list subpanel"} tabIndex={-1}
|
|
73
|
+
onKeyDown={this.onKeyDown} onFocus={this.onFocus}
|
|
74
|
+
>
|
|
75
|
+
<this.props.subPanel closeSubPanel={this.closeSubPanel} subPanelData={this.props.subPanelData} />
|
|
63
76
|
</div>
|
|
64
77
|
);
|
|
65
78
|
}
|
|
@@ -69,11 +82,11 @@ class ToolbarSubPanel extends React.Component {
|
|
|
69
82
|
}
|
|
70
83
|
|
|
71
84
|
ToolbarSubPanel.propTypes = {
|
|
72
|
-
subPanel: PropTypes.any,
|
|
85
|
+
subPanel: PropTypes.any.isRequired,
|
|
73
86
|
subPanelData: PropTypes.object,
|
|
74
87
|
closeSubArea: PropTypes.func,
|
|
75
88
|
setToolbarFocusAction: PropTypes.func,
|
|
76
|
-
actionItemRect: PropTypes.object
|
|
89
|
+
actionItemRect: PropTypes.object,
|
|
77
90
|
expandDirection: PropTypes.string.isRequired,
|
|
78
91
|
containingDivId: PropTypes.string
|
|
79
92
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* Copyright
|
|
2
|
+
* Copyright 2024 Elyra Authors
|
|
3
3
|
*
|
|
4
4
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
5
|
* you may not use this file except in compliance with the License.
|
|
@@ -15,20 +15,25 @@
|
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
17
|
// These utility functions are used by both toolbar-sub-menu.jsx AND
|
|
18
|
-
// toolbar-sub-panel.jsx to position the
|
|
19
|
-
// to the parent actionItemRect, passed in, in the direction
|
|
20
|
-
// the expandDirection parameter and constrained within
|
|
21
|
-
// specified by the containingDivId parameter.
|
|
18
|
+
// toolbar-sub-panel.jsx to position the sub-area (sub-menu or sub-panel)
|
|
19
|
+
// relative to the parent actionItemRect, passed in, in the direction
|
|
20
|
+
// indicated by the expandDirection parameter and constrained within
|
|
21
|
+
// the <div> specified by the containingDivId parameter.
|
|
22
22
|
|
|
23
23
|
|
|
24
24
|
// Adjust the position of the sub-area to make sure it doesn't extend
|
|
25
25
|
// outside the containing divs boundary. We need to do this after the subarea
|
|
26
26
|
// has been mounted so we can query its size and position.
|
|
27
27
|
export function adjustSubAreaPosition(areaRef, containingDivId, expandDirection, actionItemRect) {
|
|
28
|
+
if (!areaRef || !actionItemRect || !containingDivId) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
28
31
|
const containingDiv = document.getElementById(containingDivId);
|
|
29
|
-
const containingDivRect = containingDiv
|
|
32
|
+
const containingDivRect = containingDiv
|
|
33
|
+
? containingDiv.getBoundingClientRect()
|
|
34
|
+
: { top: -1000, bottom: 1000, left: -1000, right: 1000 }; // To enable Jest tests.
|
|
30
35
|
|
|
31
|
-
const thisAreaRect = areaRef.
|
|
36
|
+
const thisAreaRect = areaRef.getBoundingClientRect();
|
|
32
37
|
|
|
33
38
|
const outsideBottom = thisAreaRect.bottom - containingDivRect.bottom;
|
|
34
39
|
const outsideRight = thisAreaRect.right - containingDivRect.right;
|
|
@@ -40,28 +45,32 @@ export function adjustSubAreaPosition(areaRef, containingDivId, expandDirection,
|
|
|
40
45
|
? actionItemRect.top - thisAreaRect.height
|
|
41
46
|
: actionItemRect.bottom - outsideBottom;
|
|
42
47
|
|
|
43
|
-
areaRef.
|
|
48
|
+
areaRef.style.top = newTop + "px";
|
|
44
49
|
}
|
|
45
50
|
|
|
46
51
|
if (outsideRight > 0) {
|
|
47
|
-
const newLeft = actionItemRect.left - outsideRight
|
|
48
|
-
areaRef.
|
|
52
|
+
const newLeft = actionItemRect.left - outsideRight;
|
|
53
|
+
areaRef.style.left = newLeft + "px";
|
|
49
54
|
}
|
|
50
55
|
|
|
51
56
|
} else {
|
|
52
57
|
if (outsideBottom > 0) {
|
|
53
58
|
const newTop = thisAreaRect.top - outsideBottom - 2;
|
|
54
|
-
areaRef.
|
|
59
|
+
areaRef.style.top = newTop + "px";
|
|
55
60
|
}
|
|
56
61
|
|
|
57
62
|
if (outsideRight > 0) {
|
|
58
63
|
const newLeft = actionItemRect.left - thisAreaRect.width;
|
|
59
|
-
areaRef.
|
|
64
|
+
areaRef.style.left = newLeft + "px";
|
|
60
65
|
}
|
|
61
66
|
}
|
|
62
67
|
}
|
|
63
68
|
|
|
64
69
|
export function generateSubAreaStyle(expandDirection, actionItemRect) {
|
|
70
|
+
if (!actionItemRect) {
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
|
|
65
74
|
if (expandDirection === "vertical") {
|
|
66
75
|
return {
|
|
67
76
|
top: actionItemRect.bottom + 1,
|
package/src/toolbar/toolbar.jsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* Copyright 2017-
|
|
2
|
+
* Copyright 2017-2024 Elyra Authors
|
|
3
3
|
*
|
|
4
4
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
5
|
* you may not use this file except in compliance with the License.
|
|
@@ -69,6 +69,7 @@ class Toolbar extends React.Component {
|
|
|
69
69
|
this.generateToolbarItems = this.generateToolbarItems.bind(this);
|
|
70
70
|
this.setFocusAction = this.setFocusAction.bind(this);
|
|
71
71
|
this.setFocusOnItem = this.setFocusOnItem.bind(this);
|
|
72
|
+
this.closeAnyOpenSubArea = this.closeAnyOpenSubArea.bind(this);
|
|
72
73
|
}
|
|
73
74
|
|
|
74
75
|
// If, after updating, we are left in a situation where this.state.focusAction
|
|
@@ -76,13 +77,12 @@ class Toolbar extends React.Component {
|
|
|
76
77
|
// item. This might happen when an item with focus is activated and the action it
|
|
77
78
|
// performs causes itself to become disabled. For example, if the delete item is
|
|
78
79
|
// activated the selected objects are deleted and since no objects are now selected
|
|
79
|
-
// the delete item (which has focus) will become disabled.
|
|
80
|
+
// the delete item (which has focus) will become disabled. It may also happen if the
|
|
81
|
+
// toolbar config is updated and the current focusAction item is removed.
|
|
80
82
|
componentDidUpdate() {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
this.setFocusOnFirstItem();
|
|
85
|
-
}
|
|
83
|
+
const index = this.getFocusableItemRefs().findIndex((item) => this.getRefAction(item) === this.state.focusAction);
|
|
84
|
+
if (index === -1) {
|
|
85
|
+
this.setFocusOnFirstItem();
|
|
86
86
|
}
|
|
87
87
|
}
|
|
88
88
|
|
|
@@ -106,11 +106,15 @@ class Toolbar extends React.Component {
|
|
|
106
106
|
}
|
|
107
107
|
}
|
|
108
108
|
|
|
109
|
-
// When focus leaves the toolbar make sure we record it
|
|
110
|
-
// accidentally
|
|
111
|
-
// the focus elsewhere.
|
|
112
|
-
onBlur() {
|
|
113
|
-
|
|
109
|
+
// When focus leaves the toolbar make sure we record it. This prevents
|
|
110
|
+
// us accidentally setting focus on a toolbar item when the toolbar
|
|
111
|
+
// re-renders with the focus elsewhere.
|
|
112
|
+
onBlur(evt) {
|
|
113
|
+
// If the focus is being moved to an object outside the toolbar div
|
|
114
|
+
// we set isFocusInToolbar to false.
|
|
115
|
+
if (!evt.relatedTarget?.closest(".toolbar-div")) {
|
|
116
|
+
this.isFocusInToolbar = false;
|
|
117
|
+
}
|
|
114
118
|
}
|
|
115
119
|
|
|
116
120
|
// This is called when the user presses a key with focus on one of the
|
|
@@ -136,17 +140,48 @@ class Toolbar extends React.Component {
|
|
|
136
140
|
}
|
|
137
141
|
|
|
138
142
|
// When the toolbar resizes, check each toolbar item to see if it has
|
|
139
|
-
//
|
|
143
|
+
// an open sub-area and, if that item is not a focusable item, close
|
|
144
|
+
// the sub-area. The item may no longer be focusable it is it was wrapped
|
|
145
|
+
// into the overflow menu. Also, check to see if the current focus action
|
|
146
|
+
// item is focusable and, if not, set focus on the first focusable item.
|
|
140
147
|
onToolbarResize() {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
148
|
+
const focusableItemRefs = this.getFocusableItemRefs();
|
|
149
|
+
// Note: isFocusActionFocusable needs to be calculated here before any
|
|
150
|
+
// update to the toolbar caused by the code in the subsequent if ststement.
|
|
151
|
+
const isFocusActionFocusable = this.isFocusActionFocusable(this.state.focusAction, focusableItemRefs);
|
|
152
|
+
const refWithOpenSubArea = this.getRefWithOpenSubArea();
|
|
153
|
+
|
|
154
|
+
if (refWithOpenSubArea) {
|
|
155
|
+
const action = refWithOpenSubArea.current.getAction();
|
|
156
|
+
const isFocusActionWithOpenSubAreaFocusable = this.isFocusActionFocusable(action, focusableItemRefs);
|
|
157
|
+
|
|
158
|
+
if (!isFocusActionWithOpenSubAreaFocusable) {
|
|
159
|
+
refWithOpenSubArea.current.closeSubArea();
|
|
160
|
+
|
|
161
|
+
} else {
|
|
162
|
+
// This forces a refresh that will cause the position of any
|
|
163
|
+
// open sub-area to be recaulculated based on the new toolbar width.
|
|
164
|
+
this.setFocusAction(this.state.focusAction);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
144
167
|
|
|
145
|
-
|
|
168
|
+
// If the focus action item is not focusable (maybe because it has been
|
|
169
|
+
// moved into the overflow menu) then set focus on the first focusable item.
|
|
170
|
+
if (!isFocusActionFocusable) {
|
|
146
171
|
this.setFocusOnFirstItem();
|
|
147
172
|
}
|
|
148
173
|
}
|
|
149
174
|
|
|
175
|
+
// Returns the ref to any item that currently has an open sub-area or null
|
|
176
|
+
// if no item has an open sub-area.
|
|
177
|
+
getRefWithOpenSubArea() {
|
|
178
|
+
let subAreaOpenRef = this.leftItemRefs.find((ref) => ref.current.isSubAreaDisplayed());
|
|
179
|
+
if (!subAreaOpenRef) {
|
|
180
|
+
subAreaOpenRef = this.rightItemRefs.find((ref) => ref.current.isSubAreaDisplayed());
|
|
181
|
+
}
|
|
182
|
+
return subAreaOpenRef;
|
|
183
|
+
}
|
|
184
|
+
|
|
150
185
|
// Either sets the focus on the item for the action passed in or, if
|
|
151
186
|
// no action is passed in, set the focus on the current focusAction.
|
|
152
187
|
// Setting the current focusAction is used to return focus back to an
|
|
@@ -192,18 +227,18 @@ class Toolbar extends React.Component {
|
|
|
192
227
|
|
|
193
228
|
getPreviousItemRef(focusableItemRefs) {
|
|
194
229
|
const index = focusableItemRefs.findIndex((item) => this.getRefAction(item) === this.state.focusAction);
|
|
195
|
-
if (index
|
|
196
|
-
return focusableItemRefs[
|
|
230
|
+
if (index === 0) {
|
|
231
|
+
return focusableItemRefs[focusableItemRefs.length - 1];
|
|
197
232
|
}
|
|
198
|
-
return
|
|
233
|
+
return focusableItemRefs[index - 1];
|
|
199
234
|
}
|
|
200
235
|
|
|
201
236
|
getNextItemRef(focusableItemRefs) {
|
|
202
237
|
const index = focusableItemRefs.findIndex((item) => this.getRefAction(item) === this.state.focusAction);
|
|
203
|
-
if (index
|
|
204
|
-
return focusableItemRefs[
|
|
238
|
+
if (index === focusableItemRefs.length - 1) {
|
|
239
|
+
return focusableItemRefs[0];
|
|
205
240
|
}
|
|
206
|
-
return
|
|
241
|
+
return focusableItemRefs[index + 1];
|
|
207
242
|
}
|
|
208
243
|
|
|
209
244
|
getRefAction(ref) {
|
|
@@ -313,6 +348,14 @@ class Toolbar extends React.Component {
|
|
|
313
348
|
return index;
|
|
314
349
|
}
|
|
315
350
|
|
|
351
|
+
// Returns true of the current focus action item is one of the focusable
|
|
352
|
+
// items. (It may not be if it has been placed in the overflow menu).
|
|
353
|
+
isFocusActionFocusable(focusAction, focusableItemRefs) {
|
|
354
|
+
const indexFocusAction = focusableItemRefs.findIndex((ref) =>
|
|
355
|
+
ref.current.props.actionObj?.action === focusAction);
|
|
356
|
+
return indexFocusAction > -1;
|
|
357
|
+
}
|
|
358
|
+
|
|
316
359
|
// Returns a reference to the first item that is not on the
|
|
317
360
|
// top (visible) row of the toolbar.
|
|
318
361
|
findFirstRightItemRefNotOnTopRow() {
|
|
@@ -386,6 +429,7 @@ class Toolbar extends React.Component {
|
|
|
386
429
|
toolbarFocusAction={this.state.focusAction}
|
|
387
430
|
setToolbarFocusAction={this.setFocusOnItem}
|
|
388
431
|
isFocusInToolbar={this.isFocusInToolbar}
|
|
432
|
+
closeAnyOpenSubArea={this.closeAnyOpenSubArea}
|
|
389
433
|
size={this.props.size}
|
|
390
434
|
/>
|
|
391
435
|
);
|
|
@@ -421,6 +465,7 @@ class Toolbar extends React.Component {
|
|
|
421
465
|
toolbarFocusAction={this.state.focusAction}
|
|
422
466
|
setToolbarFocusAction={this.setFocusOnItem}
|
|
423
467
|
isFocusInToolbar={this.isFocusInToolbar}
|
|
468
|
+
closeAnyOpenSubArea={this.closeAnyOpenSubArea}
|
|
424
469
|
/>
|
|
425
470
|
);
|
|
426
471
|
|
|
@@ -440,8 +485,17 @@ class Toolbar extends React.Component {
|
|
|
440
485
|
return subMenuActions;
|
|
441
486
|
}
|
|
442
487
|
|
|
443
|
-
|
|
444
|
-
|
|
488
|
+
closeAnyOpenSubArea() {
|
|
489
|
+
this.leftItemRefs.forEach((ref) => this.closeSubAreaOnRef(ref));
|
|
490
|
+
this.rightItemRefs.forEach((ref) => this.closeSubAreaOnRef(ref));
|
|
491
|
+
this.overflowItemRefs.forEach((ref) => this.closeOverflowMenuOnRef(ref));
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
closeSubAreaOnRef(ref) {
|
|
495
|
+
if (ref.current.props.actionObj.setExtIsSubAreaDisplayed) {
|
|
496
|
+
ref.current.props.actionObj.setExtIsSubAreaDisplayed(false);
|
|
497
|
+
|
|
498
|
+
} else if (ref.current.state.subAreaDisplayed) {
|
|
445
499
|
ref.current.closeSubArea();
|
|
446
500
|
}
|
|
447
501
|
}
|