@elyra/canvas 12.40.1 → 12.42.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.
Files changed (173) hide show
  1. package/dist/{_baseIteratee-05ccf6a8.js → _baseIteratee-148093b7.js} +3 -3
  2. package/dist/{_baseIteratee-05ccf6a8.js.map → _baseIteratee-148093b7.js.map} +1 -1
  3. package/dist/{canvas-constants-079172c0.js → canvas-constants-13b58448.js} +2 -2
  4. package/dist/{canvas-constants-079172c0.js.map → canvas-constants-13b58448.js.map} +1 -1
  5. package/dist/canvas-controller-a53943e4.js +2 -0
  6. package/dist/canvas-controller-a53943e4.js.map +1 -0
  7. package/dist/canvas-controller-cb1d7420.js +2 -0
  8. package/dist/canvas-controller-cb1d7420.js.map +1 -0
  9. package/dist/common-canvas-42027a3f.js +2 -0
  10. package/dist/common-canvas-42027a3f.js.map +1 -0
  11. package/dist/common-canvas-f758ff42.js +2 -0
  12. package/dist/common-canvas-f758ff42.js.map +1 -0
  13. package/dist/common-canvas.es.js +1 -1
  14. package/dist/common-canvas.es.js.map +1 -1
  15. package/dist/common-canvas.js +1 -1
  16. package/dist/common-canvas.js.map +1 -1
  17. package/dist/common-properties-2e1b7ec7.js +2 -0
  18. package/dist/common-properties-2e1b7ec7.js.map +1 -0
  19. package/dist/common-properties-5e8870e3.js +2 -0
  20. package/dist/common-properties-5e8870e3.js.map +1 -0
  21. package/dist/context-menu-wrapper-49f9a1af.js +2 -0
  22. package/dist/context-menu-wrapper-49f9a1af.js.map +1 -0
  23. package/dist/context-menu-wrapper-5d6a399f.js +2 -0
  24. package/dist/context-menu-wrapper-5d6a399f.js.map +1 -0
  25. package/dist/{datarecord-metadata-v3-schema-59505bc5.js → datarecord-metadata-v3-schema-98ec66e9.js} +2 -2
  26. package/dist/{datarecord-metadata-v3-schema-59505bc5.js.map → datarecord-metadata-v3-schema-98ec66e9.js.map} +1 -1
  27. package/dist/{flexible-table-5ee2a42b.js → flexible-table-35e9922a.js} +2 -2
  28. package/dist/{flexible-table-5ee2a42b.js.map → flexible-table-35e9922a.js.map} +1 -1
  29. package/dist/{flexible-table-562ae288.js → flexible-table-7c7de0f9.js} +1 -1
  30. package/dist/{flexible-table-562ae288.js.map → flexible-table-7c7de0f9.js.map} +1 -1
  31. package/dist/{icon-0390f1fe.js → icon-9edff40c.js} +2 -2
  32. package/dist/{icon-0390f1fe.js.map → icon-9edff40c.js.map} +1 -1
  33. package/dist/{index-fe8d4201.js → index-94fec521.js} +2 -2
  34. package/dist/index-94fec521.js.map +1 -0
  35. package/dist/index-e2f8a935.js +2 -0
  36. package/dist/index-e2f8a935.js.map +1 -0
  37. package/dist/{isArrayLikeObject-36898fcb.js → isArrayLikeObject-7a30aa4b.js} +2 -2
  38. package/dist/{isArrayLikeObject-36898fcb.js.map → isArrayLikeObject-7a30aa4b.js.map} +1 -1
  39. package/dist/lib/canvas-controller.es.js +1 -1
  40. package/dist/lib/canvas-controller.js +1 -1
  41. package/dist/lib/canvas.es.js +1 -1
  42. package/dist/lib/canvas.js +1 -1
  43. package/dist/lib/context-menu.es.js +1 -1
  44. package/dist/lib/context-menu.js +1 -1
  45. package/dist/lib/properties/field-picker.es.js +1 -1
  46. package/dist/lib/properties/field-picker.js +1 -1
  47. package/dist/lib/properties/flexible-table.es.js +1 -1
  48. package/dist/lib/properties/flexible-table.js +1 -1
  49. package/dist/lib/properties.es.js +1 -1
  50. package/dist/lib/properties.js +1 -1
  51. package/dist/lib/tooltip.es.js +1 -1
  52. package/dist/lib/tooltip.es.js.map +1 -1
  53. package/dist/lib/tooltip.js +1 -1
  54. package/dist/lib/tooltip.js.map +1 -1
  55. package/dist/styles/common-canvas.min.css +1 -1
  56. package/dist/styles/common-canvas.min.css.map +1 -1
  57. package/dist/toolbar-6acda0a2.js +2 -0
  58. package/dist/toolbar-6acda0a2.js.map +1 -0
  59. package/dist/toolbar-d5647da2.js +2 -0
  60. package/dist/toolbar-d5647da2.js.map +1 -0
  61. package/locales/common-properties/locales/de.json +1 -0
  62. package/locales/common-properties/locales/es.json +1 -0
  63. package/locales/common-properties/locales/fr.json +1 -0
  64. package/locales/common-properties/locales/it.json +1 -0
  65. package/locales/common-properties/locales/ja.json +1 -0
  66. package/locales/common-properties/locales/ko.json +1 -0
  67. package/locales/common-properties/locales/pt-br.json +1 -0
  68. package/locales/common-properties/locales/sv.json +1 -0
  69. package/locales/common-properties/locales/zh-CN.json +1 -0
  70. package/locales/common-properties/locales/zh-TW.json +1 -0
  71. package/package.json +12 -4
  72. package/src/color-picker/color-picker.jsx +92 -17
  73. package/src/command-actions/arrangeLayoutAction.js +7 -6
  74. package/src/command-actions/attachNodeToLinksAction.js +4 -4
  75. package/src/command-actions/collapseSuperNodeInPlaceAction.js +5 -5
  76. package/src/command-actions/colorSelectedObjectsAction.js +4 -4
  77. package/src/command-actions/commonPropertiesAction.js +1 -1
  78. package/src/command-actions/convertSuperNodeExternalToLocalAction.js +4 -4
  79. package/src/command-actions/convertSuperNodeLocalToExternalAction.js +4 -4
  80. package/src/command-actions/createAutoNodeAction.js +14 -5
  81. package/src/command-actions/createCommentAction.js +4 -10
  82. package/src/command-actions/createCommentLinkAction.js +4 -4
  83. package/src/command-actions/createNodeAction.js +13 -4
  84. package/src/command-actions/createNodeAttachLinksAction.js +4 -4
  85. package/src/command-actions/createNodeLinkAction.js +13 -4
  86. package/src/command-actions/createNodeLinkDetachedAction.js +4 -4
  87. package/src/command-actions/createNodeOnLinkAction.js +4 -4
  88. package/src/command-actions/createSuperNodeAction.js +7 -7
  89. package/src/command-actions/deconstructSuperNodeAction.js +5 -5
  90. package/src/command-actions/deleteLinkAction.js +4 -4
  91. package/src/command-actions/deleteObjectsAction.js +15 -6
  92. package/src/command-actions/disconnectObjectsAction.js +13 -4
  93. package/src/command-actions/displayPreviousPipelineAction.js +4 -4
  94. package/src/command-actions/displaySubPipelineAction.js +4 -4
  95. package/src/command-actions/editCommentAction.js +4 -4
  96. package/src/command-actions/editDecorationLabelAction.js +4 -4
  97. package/src/command-actions/expandSuperNodeInPlaceAction.js +5 -5
  98. package/src/command-actions/insertNodeIntoLinkAction.js +4 -4
  99. package/src/command-actions/moveObjectsAction.js +4 -4
  100. package/src/command-actions/pasteAction.js +16 -7
  101. package/src/command-actions/saveToPaletteAction.js +4 -4
  102. package/src/command-actions/setLinksStyleAction.js +4 -4
  103. package/src/command-actions/setNodeLabelAction.js +4 -4
  104. package/src/command-actions/setObjectsStyleAction.js +4 -4
  105. package/src/command-actions/sizeAndPositionObjectsAction.js +4 -4
  106. package/src/command-actions/updateLinkAction.js +4 -4
  107. package/src/common-canvas/canvas-controller-menu-utils.js +1 -1
  108. package/src/common-canvas/canvas-controller.js +78 -62
  109. package/src/common-canvas/cc-central-items.jsx +1 -1
  110. package/src/common-canvas/cc-context-toolbar.jsx +9 -13
  111. package/src/common-canvas/cc-toolbar.jsx +2 -0
  112. package/src/common-canvas/svg-canvas-d3.scss +1 -1
  113. package/src/common-canvas/svg-canvas-renderer.js +6 -2
  114. package/src/common-canvas/svg-canvas-utils-drag-det-link.js +8 -1
  115. package/src/common-canvas/svg-canvas-utils-drag-new-link.js +1 -1
  116. package/src/common-properties/components/table-buttons/table-buttons.scss +0 -1
  117. package/src/common-properties/components/wide-flyout/wide-flyout.scss +1 -2
  118. package/src/common-properties/constants/form-constants.js +1 -0
  119. package/src/common-properties/controls/control-factory.js +6 -1
  120. package/src/common-properties/controls/controls.scss +1 -0
  121. package/src/common-properties/controls/expression/expression-builder/expression-builder.jsx +32 -26
  122. package/src/common-properties/controls/expression/expression.jsx +146 -117
  123. package/src/common-properties/controls/expression/expression.scss +43 -45
  124. package/src/common-properties/controls/expression/languages/CLEM-hint.js +86 -159
  125. package/src/common-properties/controls/expression/languages/python-hint.js +53 -104
  126. package/src/common-properties/controls/expression/languages/r-hint.js +55 -130
  127. package/src/{toolbar/toolbar-utils.js → common-properties/controls/slider/index.js} +2 -17
  128. package/src/common-properties/controls/slider/slider.jsx +96 -0
  129. package/src/common-properties/controls/slider/slider.scss +44 -0
  130. package/src/common-properties/form/ControlInfo.js +6 -0
  131. package/src/common-properties/form/EditorForm.js +2 -0
  132. package/src/common-properties/form/ParameterInfo.js +8 -0
  133. package/src/common-properties/properties-controller.js +16 -5
  134. package/src/context-menu/common-context-menu.jsx +4 -1
  135. package/src/index.js +12 -2
  136. package/src/object-model/redux/canvas-store.js +4 -3
  137. package/src/toolbar/toolbar-action-item.jsx +90 -314
  138. package/src/toolbar/toolbar-button-item.jsx +354 -0
  139. package/src/toolbar/toolbar-divider-item.jsx +3 -4
  140. package/src/toolbar/toolbar-overflow-item.jsx +82 -36
  141. package/src/toolbar/toolbar-sub-menu-item.jsx +235 -0
  142. package/src/toolbar/toolbar-sub-menu.jsx +254 -0
  143. package/src/toolbar/toolbar-sub-panel.jsx +81 -0
  144. package/src/toolbar/toolbar-sub-utils.js +77 -0
  145. package/src/toolbar/toolbar.jsx +330 -146
  146. package/src/toolbar/toolbar.scss +22 -15
  147. package/src/tooltip/tooltip.jsx +21 -2
  148. package/stats.html +1 -1
  149. package/dist/canvas-controller-1e71b405.js +0 -2
  150. package/dist/canvas-controller-1e71b405.js.map +0 -1
  151. package/dist/canvas-controller-4bed5320.js +0 -2
  152. package/dist/canvas-controller-4bed5320.js.map +0 -1
  153. package/dist/common-canvas-318df796.js +0 -2
  154. package/dist/common-canvas-318df796.js.map +0 -1
  155. package/dist/common-canvas-d41ba910.js +0 -2
  156. package/dist/common-canvas-d41ba910.js.map +0 -1
  157. package/dist/common-properties-6e904e3b.js +0 -2
  158. package/dist/common-properties-6e904e3b.js.map +0 -1
  159. package/dist/common-properties-c91bfb31.js +0 -2
  160. package/dist/common-properties-c91bfb31.js.map +0 -1
  161. package/dist/context-menu-wrapper-3a7fdec8.js +0 -2
  162. package/dist/context-menu-wrapper-3a7fdec8.js.map +0 -1
  163. package/dist/context-menu-wrapper-fc85d853.js +0 -2
  164. package/dist/context-menu-wrapper-fc85d853.js.map +0 -1
  165. package/dist/index-8e8b8729.js +0 -2
  166. package/dist/index-8e8b8729.js.map +0 -1
  167. package/dist/index-fe8d4201.js.map +0 -1
  168. package/dist/toolbar-b01e6749.js +0 -2
  169. package/dist/toolbar-b01e6749.js.map +0 -1
  170. package/dist/toolbar-fd4e4a3a.js +0 -2
  171. package/dist/toolbar-fd4e4a3a.js.map +0 -1
  172. package/src/toolbar/toolbar-action-sub-area.jsx +0 -126
  173. package/src/toolbar/toolbar-overflow-menu.jsx +0 -77
@@ -0,0 +1,235 @@
1
+ /*
2
+ * Copyright 2017-2023 Elyra Authors
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ import React from "react";
18
+ import PropTypes from "prop-types";
19
+
20
+ import ToolbarButtonItem from "./toolbar-button-item.jsx";
21
+
22
+ import classNames from "classnames";
23
+ import ToolbarSubMenu from "./toolbar-sub-menu.jsx";
24
+ import ToolbarSubPanel from "./toolbar-sub-panel.jsx";
25
+
26
+ class ToolbarSubMenuItem extends React.Component {
27
+ constructor(props) {
28
+ super(props);
29
+
30
+ this.state = {
31
+ subAreaDisplayed: false
32
+ };
33
+
34
+ this.divRef = React.createRef();
35
+
36
+ this.actionClickHandler = this.actionClickHandler.bind(this);
37
+ this.onMouseEnter = this.onMouseEnter.bind(this);
38
+ this.onMouseLeave = this.onMouseLeave.bind(this);
39
+ this.openSubArea = this.openSubArea.bind(this);
40
+ this.closeSubArea = this.closeSubArea.bind(this);
41
+ this.clickOutside = this.clickOutside.bind(this);
42
+ }
43
+
44
+ // We must remove the eventListener in case this class is unmounted due
45
+ // to the toolbar getting redrawn.
46
+ componentWillUnmount() {
47
+ document.removeEventListener("click", this.clickOutside, false);
48
+ }
49
+
50
+ onMouseEnter(evt) {
51
+ if (this.props.actionObj.subMenu || this.props.actionObj.subPanel) {
52
+ this.openSubArea();
53
+ }
54
+ }
55
+
56
+ onMouseLeave(evt) {
57
+ if (this.props.actionObj.subMenu || this.props.actionObj.subPanel) {
58
+ this.closeSubArea();
59
+ }
60
+ }
61
+
62
+ clickOutside(evt) {
63
+ if (this.state.subAreaDisplayed) {
64
+ const items = document.getElementsByClassName(this.generateActionName());
65
+ const isOver = items && items.length > 0 ? items[0].contains(evt.target) : false;
66
+
67
+ if (!isOver) {
68
+ this.closeSubArea();
69
+ }
70
+ }
71
+ }
72
+
73
+ openSubArea() {
74
+ this.setState({ subAreaDisplayed: true });
75
+ }
76
+
77
+ closeSubArea(checkCloseSubAreaOnClick) {
78
+ if (!checkCloseSubAreaOnClick || this.props.actionObj.closeSubAreaOnClick) {
79
+ this.setState({ subAreaDisplayed: false });
80
+ }
81
+ }
82
+
83
+ actionClickHandler(evt) {
84
+ if (this.props.actionObj.subMenu || this.props.actionObj.subPanel) {
85
+ if (this.state.subAreaDisplayed) {
86
+ document.removeEventListener("click", this.clickOutside, false);
87
+ this.closeSubArea();
88
+ } else {
89
+ document.addEventListener("click", this.clickOutside, false);
90
+ this.openSubArea();
91
+ }
92
+
93
+ } else {
94
+ evt.stopPropagation();
95
+ if (this.props.isInCascadeMenu) {
96
+ this.props.closeParentSubArea();
97
+ this.props.setSubMenuFocus();
98
+
99
+ } else if (this.props.isInOverflowMenu) {
100
+ this.props.setSubMenuFocus(this.props.actionObj.action);
101
+
102
+ } else {
103
+ this.props.closeParentSubArea();
104
+ this.props.setToolbarFocusAction(); // Resets the toolbar focus action
105
+ }
106
+ this.props.toolbarActionHandler(this.props.actionObj.action, evt);
107
+ }
108
+ }
109
+
110
+ generateActionName() {
111
+ return this.props.actionObj.action + "-action";
112
+ }
113
+
114
+ // Returns a sub-area for a cascading menu item. The sub-area can be either a
115
+ // sub-panel which is a div contaiing whatever the caller passes in within the
116
+ // supPanel field OR a sub-menu which is a list of options which is created
117
+ // from the array of items the caller passes in the subMenu field.
118
+ generateSubArea() {
119
+ const actionItemRect = this.divRef.current.getBoundingClientRect();
120
+
121
+ if (this.props.actionObj.subPanel) {
122
+ return (
123
+ <ToolbarSubPanel
124
+ subPanel={this.props.actionObj.subPanel}
125
+ subPanelData={this.props.actionObj.subPanelData}
126
+ closeSubArea={this.closeSubArea}
127
+ actionItemRect={actionItemRect}
128
+ expandDirection={"horizontal"}
129
+ containingDivId={this.props.containingDivId}
130
+ />
131
+ );
132
+ }
133
+ return (
134
+ <ToolbarSubMenu
135
+ subMenuActions={this.props.actionObj.subMenu}
136
+ instanceId={this.props.instanceId}
137
+ toolbarActionHandler={this.props.toolbarActionHandler}
138
+ setSubMenuFocus={this.props.setSubMenuFocus}
139
+ closeSubArea={this.closeSubArea}
140
+ actionItemRect={actionItemRect}
141
+ expandDirection={"horizontal"}
142
+ containingDivId={this.props.containingDivId}
143
+ parentSelector={this.generateSelector()}
144
+ isCascadeMenu
145
+ size={this.props.size}
146
+ />
147
+ );
148
+ }
149
+
150
+ generateSelector() {
151
+ return ".toolbar-sub-menu-item";
152
+ }
153
+
154
+ render() {
155
+ const actionObj = this.props.actionObj;
156
+ const actionName = this.generateActionName();
157
+ const kindAsClass = actionObj.kind ? actionObj.kind : "default";
158
+
159
+ const itemClassName = classNames(
160
+ { "toolbar-sub-menu-item": true,
161
+ "toolbar-sub-menu-jsx-item": actionObj.jsx,
162
+ "toolbar-item-selected": actionObj.isSelected },
163
+ kindAsClass,
164
+ actionName);
165
+
166
+ const subArea = this.state.subAreaDisplayed ? this.generateSubArea() : null;
167
+
168
+ return (
169
+ <div ref={this.divRef} className={itemClassName} data-toolbar-action={actionObj.action}
170
+ onMouseEnter={this.onMouseEnter} onMouseLeave={this.onMouseLeave} onKeyDown={this.onKeyDown}
171
+ >
172
+ <div>
173
+ <ToolbarButtonItem
174
+ actionObj={actionObj}
175
+ actionName={this.generateActionName()}
176
+ instanceId={this.props.instanceId}
177
+ isInMenu
178
+ subAreaDisplayed={this.state.subAreaDisplayed}
179
+ actionClickHandler={this.actionClickHandler}
180
+ buttonFocusAction={this.props.subMenuFocusAction}
181
+ isFocusInToolbar // Focus must be in toolbar for this sub-menu item to appear
182
+ size={this.props.size}
183
+ />
184
+ </div>
185
+ {subArea}
186
+ </div>
187
+ );
188
+ }
189
+ }
190
+
191
+ ToolbarSubMenuItem.propTypes = {
192
+ actionObj: PropTypes.shape({
193
+ action: PropTypes.string.isRequired,
194
+ label: PropTypes.oneOfType([
195
+ PropTypes.string,
196
+ PropTypes.object
197
+ ]),
198
+ incLabelWithIcon: PropTypes.oneOf(["no", "before", "after"]),
199
+ enable: PropTypes.bool,
200
+ iconEnabled: PropTypes.oneOfType([
201
+ PropTypes.string,
202
+ PropTypes.object
203
+ ]),
204
+ iconDisabled: PropTypes.oneOfType([
205
+ PropTypes.string,
206
+ PropTypes.object
207
+ ]),
208
+ className: PropTypes.string,
209
+ textContent: PropTypes.string,
210
+ isSelected: PropTypes.bool,
211
+ kind: PropTypes.string,
212
+ closeSubAreaOnClick: PropTypes.bool,
213
+ subMenu: PropTypes.array,
214
+ subPanel: PropTypes.any,
215
+ subPanelData: PropTypes.object,
216
+ jsx: PropTypes.object,
217
+ tooltip: PropTypes.oneOfType([
218
+ PropTypes.string,
219
+ PropTypes.object,
220
+ PropTypes.func
221
+ ])
222
+ }),
223
+ toolbarActionHandler: PropTypes.func.isRequired,
224
+ instanceId: PropTypes.number.isRequired,
225
+ containingDivId: PropTypes.string,
226
+ closeParentSubArea: PropTypes.func,
227
+ subMenuFocusAction: PropTypes.string,
228
+ setToolbarFocusAction: PropTypes.func,
229
+ setSubMenuFocus: PropTypes.func,
230
+ isInOverflowMenu: PropTypes.bool,
231
+ isInCascadeMenu: PropTypes.bool,
232
+ size: PropTypes.oneOf(["md", "sm"])
233
+ };
234
+
235
+ export default ToolbarSubMenuItem;
@@ -0,0 +1,254 @@
1
+ /*
2
+ * Copyright 2023 Elyra Authors
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ import React from "react";
18
+ import PropTypes from "prop-types";
19
+ import ToolbarSubMenuItem from "./toolbar-sub-menu-item.jsx";
20
+ import ToolbarDividerItem from "./toolbar-divider-item";
21
+
22
+ import { adjustSubAreaPosition, generateSubAreaStyle } from "./toolbar-sub-utils.js";
23
+
24
+ const ESC_KEY = 27;
25
+ const LEFT_ARROW_KEY = 37;
26
+ const UP_ARROW_KEY = 38;
27
+ const RIGHT_ARROW_KEY = 39;
28
+ const DOWN_ARROW_KEY = 40;
29
+
30
+ class ToolbarSubMenu extends React.Component {
31
+ constructor(props) {
32
+ super(props);
33
+
34
+ this.state = {
35
+ focusAction: "subarea"
36
+ };
37
+
38
+ this.areaRef = React.createRef();
39
+
40
+ this.onKeyDown = this.onKeyDown.bind(this);
41
+ this.setFocusAction = this.setFocusAction.bind(this);
42
+ this.setSubMenuFocus = this.setSubMenuFocus.bind(this);
43
+ }
44
+
45
+ componentDidMount() {
46
+ if (this.props.containingDivId && this.props.subMenuActions.length > 0) {
47
+ adjustSubAreaPosition(this.areaRef,
48
+ this.props.containingDivId, this.props.expandDirection, this.props.actionItemRect);
49
+ }
50
+
51
+ if (this.state.focusAction === "subarea") {
52
+ this.setFocusOnFirstItem();
53
+ }
54
+ }
55
+
56
+ componentDidUpdate() {
57
+ if (this.state.focusAction !== "subarea") {
58
+ const actionObj = this.props.subMenuActions.find((sma) => sma.action === this.state.focusAction);
59
+ if (!actionObj?.enable) {
60
+ const actionToSet = this.getClosestEnabledAction(this.state.focusAction);
61
+ if (actionToSet !== null) {
62
+ this.setFocusAction(actionToSet);
63
+ }
64
+ }
65
+ }
66
+ }
67
+
68
+ onKeyDown(evt) {
69
+ if (evt.keyCode === ESC_KEY) {
70
+ this.props.closeSubArea();
71
+ evt.stopPropagation(); // Stop propagation in a case we are a cascade menu
72
+
73
+ } else if (evt.keyCode === UP_ARROW_KEY) {
74
+ this.setFocusOnPreviousItem();
75
+ evt.stopPropagation(); // Stop propagation in a case we are a cascade menu
76
+
77
+ } else if (evt.keyCode === DOWN_ARROW_KEY) {
78
+ this.setFocusOnNextItem();
79
+ evt.stopPropagation(); // Stop propagation in a case we are a cascade menu
80
+
81
+ } else if (evt.keyCode === LEFT_ARROW_KEY) {
82
+ evt.stopPropagation(); // Stop propagation in a case we are a cascade menu
83
+
84
+ } else if (evt.keyCode === RIGHT_ARROW_KEY) {
85
+ evt.stopPropagation(); // Stop propagation in a case we are a cascade menu
86
+ }
87
+ }
88
+
89
+ setFocusOnFirstItem() {
90
+ const focusableActions = this.getFocusableActions();
91
+ if (focusableActions.length > 0) {
92
+ this.setFocusAction(focusableActions[0].action);
93
+ }
94
+ }
95
+
96
+ setFocusOnPreviousItem() {
97
+ const focusableActions = this.getFocusableActions();
98
+ const previousFocusAction = this.getPreviousFocusAction(focusableActions);
99
+ if (previousFocusAction) {
100
+ this.setFocusAction(previousFocusAction.action);
101
+ }
102
+ }
103
+
104
+ setFocusOnNextItem() {
105
+ const focusableActions = this.getFocusableActions();
106
+ const nextFocusAction = this.getNextFocusAction(focusableActions);
107
+ if (nextFocusAction) {
108
+ this.setFocusAction(nextFocusAction.action);
109
+ }
110
+ }
111
+
112
+ setFocusAction(focusAction) {
113
+ this.setState({ focusAction });
114
+ }
115
+
116
+ setSubMenuFocus(action) {
117
+ const actionToSet = action || this.state.focusAction;
118
+ this.setFocusAction(actionToSet);
119
+ }
120
+
121
+ getClosestEnabledAction(action) {
122
+ const index = this.props.subMenuActions.findIndex((sma) => sma.action === action);
123
+ let newAction = null;
124
+ let indexUp = index + 1;
125
+ let indexDown = index - 1;
126
+
127
+ while ((indexDown > -1 || indexUp < this.props.subMenuActions.length) && newAction === null) {
128
+ if (indexDown > -1 && this.props.subMenuActions[indexDown].enable) {
129
+ newAction = this.props.subMenuActions[indexDown].action;
130
+ } else {
131
+ indexDown--;
132
+ }
133
+ if (indexUp < this.props.subMenuActions.length && this.props.subMenuActions[indexUp].enable) {
134
+ newAction = this.props.subMenuActions[indexUp].action;
135
+ } else {
136
+ indexUp++;
137
+ }
138
+ }
139
+ return newAction;
140
+ }
141
+
142
+ getFocusableActions() {
143
+ const focusableActions = [];
144
+
145
+ for (let i = 0; i < this.props.subMenuActions.length; i++) {
146
+ if (this.props.subMenuActions[i].enable) {
147
+ focusableActions.push(this.props.subMenuActions[i]);
148
+ }
149
+ }
150
+
151
+ return focusableActions;
152
+ }
153
+
154
+ getPreviousFocusAction(focuableActions) {
155
+ const index = focuableActions.findIndex((fa) => fa.action === this.state.focusAction);
156
+ if (index > 0) {
157
+ return focuableActions[index - 1];
158
+ }
159
+ return focuableActions[focuableActions.length - 1];
160
+ }
161
+
162
+ getNextFocusAction(focuableActions) {
163
+ const index = focuableActions.findIndex((fa) => fa.action === this.state.focusAction);
164
+ if (index < focuableActions.length - 1) {
165
+ return focuableActions[index + 1];
166
+ }
167
+ return focuableActions[0];
168
+ }
169
+
170
+ // Generates an array of JSX objects for a sub-menu defined by the
171
+ // prop subMenuActions parameter array.
172
+ generateSubMenuItems() {
173
+ const newItems = [];
174
+
175
+ for (let i = 0; i < this.props.subMenuActions.length; i++) {
176
+ const actionObj = this.props.subMenuActions[i];
177
+ if (actionObj) {
178
+ newItems.push(this.generateSubMenuItem(actionObj, i));
179
+ }
180
+ }
181
+ return newItems;
182
+ }
183
+
184
+ // Returns JSX for a toolbar item based on the actionObj passed in.
185
+ generateSubMenuItem(actionObj, i) {
186
+ let jsx = null;
187
+
188
+ if (actionObj) {
189
+ if (actionObj.divider) {
190
+ jsx = (
191
+ <ToolbarDividerItem
192
+ key={"toolbar-item-key-" + i}
193
+ isInMenu
194
+ />
195
+ );
196
+ } else {
197
+ jsx = (
198
+ <ToolbarSubMenuItem
199
+ key={"toolbar-item-key-" + i}
200
+ actionObj={actionObj}
201
+ toolbarActionHandler={this.props.toolbarActionHandler}
202
+ closeParentSubArea={this.props.closeSubArea}
203
+ instanceId={this.props.instanceId}
204
+ containingDivId={this.props.containingDivId}
205
+ subMenuFocusAction={this.state.focusAction}
206
+ setToolbarFocusAction={this.props.setToolbarFocusAction}
207
+ setSubMenuFocus={this.props.setSubMenuFocus ? this.props.setSubMenuFocus : this.setSubMenuFocus}
208
+ size={this.props.size}
209
+ isInOverflowMenu={this.props.isOverflowMenu}
210
+ isInCascadeMenu={this.props.isCascadeMenu}
211
+ />
212
+ );
213
+ }
214
+ }
215
+ return jsx;
216
+ }
217
+
218
+ render() {
219
+ if (this.props.subMenuActions.length > 0) {
220
+ const style = this.props.isCascadeMenu
221
+ ? generateSubAreaStyle(this.props.expandDirection, this.props.actionItemRect)
222
+ : null;
223
+
224
+ this.subMenuItems = this.generateSubMenuItems();
225
+
226
+ return (
227
+ <div ref={this.areaRef} style={style} className={"toolbar-popover-list submenu"}
228
+ tabIndex={-1} onKeyDown={this.onKeyDown}
229
+ >
230
+ {this.subMenuItems}
231
+ </div>
232
+ );
233
+ }
234
+ return null;
235
+ }
236
+ }
237
+
238
+ ToolbarSubMenu.propTypes = {
239
+ subMenuActions: PropTypes.array.isRequired,
240
+ instanceId: PropTypes.number.isRequired,
241
+ toolbarActionHandler: PropTypes.func,
242
+ closeSubArea: PropTypes.func,
243
+ setToolbarFocusAction: PropTypes.func,
244
+ setSubMenuFocus: PropTypes.func,
245
+ actionItemRect: PropTypes.object.isRequired,
246
+ expandDirection: PropTypes.string.isRequired,
247
+ containingDivId: PropTypes.string,
248
+ parentSelector: PropTypes.string,
249
+ isOverflowMenu: PropTypes.bool,
250
+ isCascadeMenu: PropTypes.bool,
251
+ size: PropTypes.oneOf(["md", "sm"])
252
+ };
253
+
254
+ export default ToolbarSubMenu;
@@ -0,0 +1,81 @@
1
+ /*
2
+ * Copyright 2023 Elyra Authors
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ import React from "react";
18
+ import PropTypes from "prop-types";
19
+
20
+ import { adjustSubAreaPosition, generateSubAreaStyle } from "./toolbar-sub-utils.js";
21
+
22
+ const ESC_KEY = 27;
23
+
24
+ class ToolbarSubPanel extends React.Component {
25
+ constructor(props) {
26
+ super(props);
27
+
28
+ this.areaRef = React.createRef();
29
+
30
+ this.onClick = this.onClick.bind(this);
31
+ this.onKeyDown = this.onKeyDown.bind(this);
32
+ }
33
+
34
+ componentDidMount() {
35
+ if (this.props.containingDivId) {
36
+ adjustSubAreaPosition(this.areaRef,
37
+ this.props.containingDivId, this.props.expandDirection, this.props.actionItemRect);
38
+ }
39
+ }
40
+
41
+ onClick() {
42
+ this.props.closeSubArea();
43
+ }
44
+
45
+ onKeyDown(evt) {
46
+ if (evt.keyCode === ESC_KEY) {
47
+ this.props.closeSubArea();
48
+ evt.stopPropagation();
49
+ }
50
+ }
51
+
52
+ render() {
53
+ const style = generateSubAreaStyle(this.props.expandDirection, this.props.actionItemRect);
54
+
55
+ 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
+ return (
61
+ <div ref={this.areaRef} style={style} className={"toolbar-popover-list subpanel"} onClick={this.onClick} onKeyDown={this.onKeyDown}>
62
+ {subPanel}
63
+ </div>
64
+ );
65
+ }
66
+
67
+ return null;
68
+ }
69
+ }
70
+
71
+ ToolbarSubPanel.propTypes = {
72
+ subPanel: PropTypes.any,
73
+ subPanelData: PropTypes.object,
74
+ closeSubArea: PropTypes.func,
75
+ setToolbarFocusAction: PropTypes.func,
76
+ actionItemRect: PropTypes.object.isRequired,
77
+ expandDirection: PropTypes.string.isRequired,
78
+ containingDivId: PropTypes.string
79
+ };
80
+
81
+ export default ToolbarSubPanel;
@@ -0,0 +1,77 @@
1
+ /*
2
+ * Copyright 2023 Elyra Authors
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ // These utility functions are used by both toolbar-sub-menu.jsx AND
18
+ // toolbar-sub-panel.jsx to position the areaEf (menu or panel) relative
19
+ // to the parent actionItemRect, passed in, in the direction indicated by
20
+ // the expandDirection parameter and constrained within the <div>
21
+ // specified by the containingDivId parameter.
22
+
23
+
24
+ // Adjust the position of the sub-area to make sure it doesn't extend
25
+ // outside the containing divs boundary. We need to do this after the subarea
26
+ // has been mounted so we can query its size and position.
27
+ export function adjustSubAreaPosition(areaRef, containingDivId, expandDirection, actionItemRect) {
28
+ const containingDiv = document.getElementById(containingDivId);
29
+ const containingDivRect = containingDiv.getBoundingClientRect();
30
+
31
+ const thisAreaRect = areaRef.current.getBoundingClientRect();
32
+
33
+ const outsideBottom = thisAreaRect.bottom - containingDivRect.bottom;
34
+ const outsideRight = thisAreaRect.right - containingDivRect.right;
35
+
36
+ if (expandDirection === "vertical") {
37
+ if (outsideBottom > 0) {
38
+ const topGap = actionItemRect.top - containingDivRect.top;
39
+ const newTop = (topGap > thisAreaRect.height)
40
+ ? actionItemRect.top - thisAreaRect.height
41
+ : actionItemRect.bottom - outsideBottom;
42
+
43
+ areaRef.current.style.top = newTop + "px";
44
+ }
45
+
46
+ if (outsideRight > 0) {
47
+ const newLeft = actionItemRect.left - outsideRight - 2;
48
+ areaRef.current.style.left = newLeft + "px";
49
+ }
50
+
51
+ } else {
52
+ if (outsideBottom > 0) {
53
+ const newTop = thisAreaRect.top - outsideBottom - 2;
54
+ areaRef.current.style.top = newTop + "px";
55
+ }
56
+
57
+ if (outsideRight > 0) {
58
+ const newLeft = actionItemRect.left - thisAreaRect.width;
59
+ areaRef.current.style.left = newLeft + "px";
60
+ }
61
+ }
62
+ }
63
+
64
+ export function generateSubAreaStyle(expandDirection, actionItemRect) {
65
+ if (expandDirection === "vertical") {
66
+ return {
67
+ top: actionItemRect.bottom + 1,
68
+ left: actionItemRect.left
69
+ };
70
+ }
71
+ return {
72
+ top: actionItemRect.top - 1,
73
+ left: actionItemRect.left + actionItemRect.width
74
+ };
75
+ }
76
+
77
+