@elyra/canvas 12.31.2 → 12.32.1

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 (143) hide show
  1. package/dist/_baseIteratee-e1311552.js +8 -0
  2. package/dist/_baseIteratee-e1311552.js.map +1 -0
  3. package/dist/_baseIteratee-eabd2a94.js +7 -0
  4. package/dist/_baseIteratee-eabd2a94.js.map +1 -0
  5. package/dist/canvas-constants-72222288.js +2 -0
  6. package/dist/{canvas-constants-187a30d5.js.map → canvas-constants-72222288.js.map} +1 -1
  7. package/dist/{canvas-constants-5fb4e9b8.js → canvas-constants-903046ab.js} +2 -2
  8. package/dist/{canvas-constants-5fb4e9b8.js.map → canvas-constants-903046ab.js.map} +1 -1
  9. package/dist/canvas-controller-69928ea7.js +2 -0
  10. package/dist/canvas-controller-69928ea7.js.map +1 -0
  11. package/dist/canvas-controller-978f3e99.js +2 -0
  12. package/dist/canvas-controller-978f3e99.js.map +1 -0
  13. package/dist/common-canvas-159fb083.js +2 -0
  14. package/dist/common-canvas-159fb083.js.map +1 -0
  15. package/dist/common-canvas-318d3486.js +2 -0
  16. package/dist/common-canvas-318d3486.js.map +1 -0
  17. package/dist/common-canvas.es.js +1 -1
  18. package/dist/common-canvas.es.js.map +1 -1
  19. package/dist/common-canvas.js +1 -1
  20. package/dist/common-canvas.js.map +1 -1
  21. package/dist/common-properties-96c9c88a.js +2 -0
  22. package/dist/common-properties-96c9c88a.js.map +1 -0
  23. package/dist/common-properties-c5292c66.js +2 -0
  24. package/dist/common-properties-c5292c66.js.map +1 -0
  25. package/dist/context-menu-wrapper-5846a20e.js +2 -0
  26. package/dist/context-menu-wrapper-5846a20e.js.map +1 -0
  27. package/dist/context-menu-wrapper-ac5e8c7a.js +2 -0
  28. package/dist/context-menu-wrapper-ac5e8c7a.js.map +1 -0
  29. package/dist/datarecord-metadata-v3-schema-64329ae4.js +2 -0
  30. package/dist/datarecord-metadata-v3-schema-64329ae4.js.map +1 -0
  31. package/dist/datarecord-metadata-v3-schema-dd7370da.js +2 -0
  32. package/dist/datarecord-metadata-v3-schema-dd7370da.js.map +1 -0
  33. package/dist/flexible-table-23d61157.js +2 -0
  34. package/dist/flexible-table-23d61157.js.map +1 -0
  35. package/dist/flexible-table-4259d869.js +2 -0
  36. package/dist/flexible-table-4259d869.js.map +1 -0
  37. package/dist/icon-04f858ce.js +2 -0
  38. package/dist/{icon-111fe072.js.map → icon-04f858ce.js.map} +1 -1
  39. package/dist/icon-8cc7816d.js +2 -0
  40. package/dist/{icon-590f8eb3.js.map → icon-8cc7816d.js.map} +1 -1
  41. package/dist/index-101f9560.js +2 -0
  42. package/dist/{index-157d4b89.js.map → index-101f9560.js.map} +1 -1
  43. package/dist/index-2788d55d.js +2 -0
  44. package/dist/{index-463d0c73.js.map → index-2788d55d.js.map} +1 -1
  45. package/dist/{isArrayLikeObject-6a001191.js → isArrayLikeObject-c0bf3ab6.js} +2 -2
  46. package/dist/{isArrayLikeObject-6a001191.js.map → isArrayLikeObject-c0bf3ab6.js.map} +1 -1
  47. package/dist/lib/canvas-controller.es.js +1 -1
  48. package/dist/lib/canvas-controller.js +1 -1
  49. package/dist/lib/canvas.es.js +1 -1
  50. package/dist/lib/canvas.js +1 -1
  51. package/dist/lib/context-menu.es.js +1 -1
  52. package/dist/lib/context-menu.js +1 -1
  53. package/dist/lib/properties/field-picker.es.js +1 -1
  54. package/dist/lib/properties/field-picker.js +1 -1
  55. package/dist/lib/properties/flexible-table.es.js +1 -1
  56. package/dist/lib/properties/flexible-table.js +1 -1
  57. package/dist/lib/properties.es.js +1 -1
  58. package/dist/lib/properties.js +1 -1
  59. package/dist/lib/tooltip.es.js +1 -1
  60. package/dist/lib/tooltip.es.js.map +1 -1
  61. package/dist/lib/tooltip.js +1 -1
  62. package/dist/lib/tooltip.js.map +1 -1
  63. package/dist/styles/common-canvas.min.css +1 -1
  64. package/dist/styles/common-canvas.min.css.map +1 -1
  65. package/dist/toolbar-12f6def6.js +2 -0
  66. package/dist/toolbar-12f6def6.js.map +1 -0
  67. package/dist/toolbar-55e2020e.js +2 -0
  68. package/dist/toolbar-55e2020e.js.map +1 -0
  69. package/locales/common-properties/locales/de.json +1 -1
  70. package/locales/common-properties/locales/es.json +1 -1
  71. package/locales/common-properties/locales/fr.json +1 -1
  72. package/locales/common-properties/locales/it.json +1 -1
  73. package/locales/common-properties/locales/ja.json +1 -1
  74. package/locales/common-properties/locales/ko.json +1 -1
  75. package/locales/common-properties/locales/pt-br.json +1 -1
  76. package/locales/common-properties/locales/sv.json +1 -1
  77. package/locales/common-properties/locales/zh-CN.json +1 -1
  78. package/locales/common-properties/locales/zh-TW.json +1 -1
  79. package/package.json +1 -1
  80. package/src/color-picker/color-picker.jsx +30 -7
  81. package/src/color-picker/color-picker.scss +1 -1
  82. package/src/color-picker/index.js +18 -0
  83. package/src/command-actions/colorSelectedObjectsAction.js +2 -1
  84. package/src/common-canvas/canvas-controller-menu-utils.js +2 -2
  85. package/src/common-canvas/cc-context-toolbar.jsx +54 -33
  86. package/src/common-canvas/cc-text-toolbar.jsx +8 -15
  87. package/src/common-canvas/common-canvas.scss +8 -15
  88. package/src/common-canvas/constants/canvas-constants.js +1 -0
  89. package/src/common-canvas/svg-canvas-d3.js +1 -1
  90. package/src/common-canvas/svg-canvas-renderer.js +26 -10
  91. package/src/common-canvas/svg-canvas-utils-textarea.js +1 -1
  92. package/src/common-properties/components/flexible-table/flexible-table.jsx +8 -5
  93. package/src/common-properties/ui-conditions/conditions-utils.js +9 -0
  94. package/src/context-menu/common-context-menu.jsx +2 -2
  95. package/src/object-model/config-utils.js +20 -1
  96. package/src/object-model/pipeline-out-handler.js +3 -0
  97. package/src/toolbar/toolbar-action-item.jsx +122 -40
  98. package/src/toolbar/toolbar-action-sub-area.jsx +126 -0
  99. package/src/toolbar/toolbar-overflow-item.jsx +61 -14
  100. package/src/toolbar/toolbar-overflow-menu.jsx +77 -0
  101. package/src/toolbar/toolbar-utils.js +33 -0
  102. package/src/toolbar/toolbar.jsx +17 -24
  103. package/src/toolbar/toolbar.scss +44 -21
  104. package/src/tooltip/tooltip.jsx +5 -7
  105. package/stats.html +1 -1
  106. package/dist/_baseForOwn-33edf1a0.js +0 -8
  107. package/dist/_baseForOwn-33edf1a0.js.map +0 -1
  108. package/dist/_baseForOwn-721741a9.js +0 -7
  109. package/dist/_baseForOwn-721741a9.js.map +0 -1
  110. package/dist/canvas-constants-187a30d5.js +0 -2
  111. package/dist/canvas-controller-3edea15e.js +0 -2
  112. package/dist/canvas-controller-3edea15e.js.map +0 -1
  113. package/dist/canvas-controller-896694e3.js +0 -2
  114. package/dist/canvas-controller-896694e3.js.map +0 -1
  115. package/dist/common-canvas-88479b3e.js +0 -2
  116. package/dist/common-canvas-88479b3e.js.map +0 -1
  117. package/dist/common-canvas-df45ad40.js +0 -2
  118. package/dist/common-canvas-df45ad40.js.map +0 -1
  119. package/dist/common-properties-11732433.js +0 -2
  120. package/dist/common-properties-11732433.js.map +0 -1
  121. package/dist/common-properties-57768e63.js +0 -2
  122. package/dist/common-properties-57768e63.js.map +0 -1
  123. package/dist/context-menu-wrapper-8f68be70.js +0 -2
  124. package/dist/context-menu-wrapper-8f68be70.js.map +0 -1
  125. package/dist/context-menu-wrapper-d1ff456a.js +0 -2
  126. package/dist/context-menu-wrapper-d1ff456a.js.map +0 -1
  127. package/dist/datarecord-metadata-v3-schema-36dfc3cd.js +0 -2
  128. package/dist/datarecord-metadata-v3-schema-36dfc3cd.js.map +0 -1
  129. package/dist/datarecord-metadata-v3-schema-9e9ba30d.js +0 -2
  130. package/dist/datarecord-metadata-v3-schema-9e9ba30d.js.map +0 -1
  131. package/dist/flexible-table-2dc48a79.js +0 -2
  132. package/dist/flexible-table-2dc48a79.js.map +0 -1
  133. package/dist/flexible-table-9e66f95d.js +0 -2
  134. package/dist/flexible-table-9e66f95d.js.map +0 -1
  135. package/dist/icon-111fe072.js +0 -2
  136. package/dist/icon-590f8eb3.js +0 -2
  137. package/dist/index-157d4b89.js +0 -2
  138. package/dist/index-463d0c73.js +0 -2
  139. package/dist/toolbar-3affe026.js +0 -2
  140. package/dist/toolbar-3affe026.js.map +0 -1
  141. package/dist/toolbar-7140292d.js +0 -2
  142. package/dist/toolbar-7140292d.js.map +0 -1
  143. package/src/color-picker/color-picker-panel.jsx +0 -61
@@ -28,11 +28,13 @@ import ZoomToFit from "./../../assets/images/zoom_to_fit.svg";
28
28
  import { Button } from "carbon-components-react";
29
29
  import SVG from "react-inlinesvg";
30
30
  import classNames from "classnames";
31
- import { StopFilledAlt16, Play16, Undo16, Redo16, Chat16, ChatOff16,
31
+ import ToolbarActionSubArea from "./toolbar-action-sub-area.jsx";
32
+ import { StopFilledAlt16, Play16, Undo16, Redo16, Chat16, ChatOff16, Result16,
32
33
  Cut16, Copy16, Paste16, Edit16, ColorPalette16, Maximize16, Minimize16,
33
- Launch16, AddComment16, TrashCan16, ZoomIn16, ZoomOut16, ChevronRight16 } from "@carbon/icons-react";
34
+ Launch16, AddComment16, TrashCan16, ZoomIn16, ZoomOut16,
35
+ ChevronRight16, ChevronDown16, ChevronUp16 } from "@carbon/icons-react";
34
36
  import { TOOLBAR_STOP, TOOLBAR_RUN, TOOLBAR_UNDO, TOOLBAR_REDO,
35
- TOOLBAR_CUT, TOOLBAR_COPY, TOOLBAR_PASTE,
37
+ TOOLBAR_CUT, TOOLBAR_COPY, TOOLBAR_PASTE, TOOLBAR_CLIPBOARD,
36
38
  TOOLBAR_CREATE_COMMENT, TOOLBAR_CREATE_AUTO_COMMENT, TOOLBAR_COLOR_BACKGROUND,
37
39
  TOOLBAR_DELETE_SELECTED_OBJECTS, TOOLBAR_DELETE_LINK,
38
40
  TOOLBAR_ZOOM_IN, TOOLBAR_ZOOM_OUT, TOOLBAR_ZOOM_FIT,
@@ -47,20 +49,39 @@ class ToolbarActionItem extends React.Component {
47
49
  constructor(props) {
48
50
  super(props);
49
51
 
52
+ this.state = {
53
+ subAreaDisplayed: false
54
+ };
55
+
50
56
  this.actionClickHandler = this.actionClickHandler.bind(this);
51
57
  this.onMouseEnter = this.onMouseEnter.bind(this);
52
58
  this.onMouseLeave = this.onMouseLeave.bind(this);
59
+ this.openSubArea = this.openSubArea.bind(this);
60
+ this.closeSubArea = this.closeSubArea.bind(this);
61
+ this.clickOutside = this.clickOutside.bind(this);
62
+ }
63
+
64
+ componentDidMount() {
65
+ if (this.props.actionObj.getSubPanelCloseFn) {
66
+ this.props.actionObj.getSubPanelCloseFn(this.closeSubArea);
67
+ }
68
+ }
69
+
70
+ // We must remove the eventListener in case this class is unmounted due
71
+ // to the toolbar getting redrawn.
72
+ componentWillUnmount() {
73
+ document.removeEventListener("click", this.clickOutside, false);
53
74
  }
54
75
 
55
76
  onMouseEnter(evt) {
56
- if (this.props.actionObj.subMenu || this.props.actionObj.subPanel) {
57
- this.props.subMenuActionHandler(this.props.actionObj.action);
77
+ if ((this.props.actionObj.subMenu || this.props.actionObj.subPanel) && this.props.overflow) {
78
+ this.openSubArea();
58
79
  }
59
80
  }
60
81
 
61
82
  onMouseLeave(evt) {
62
- if (this.props.actionObj.subMenu || this.props.actionObj.subPanel) {
63
- this.props.subMenuActionHandler("");
83
+ if ((this.props.actionObj.subMenu || this.props.actionObj.subPanel) && this.props.overflow) {
84
+ this.closeSubArea();
64
85
  }
65
86
  }
66
87
 
@@ -84,6 +105,8 @@ class ToolbarActionItem extends React.Component {
84
105
  return <Undo16 disabled={disabled} />;
85
106
  case (TOOLBAR_REDO):
86
107
  return <Redo16 disabled={disabled} />;
108
+ case (TOOLBAR_CLIPBOARD):
109
+ return <Result16 disabled={disabled} />;
87
110
  case (TOOLBAR_CUT):
88
111
  return <Cut16 disabled={disabled} />;
89
112
  case (TOOLBAR_COPY):
@@ -173,8 +196,45 @@ class ToolbarActionItem extends React.Component {
173
196
  return null;
174
197
  }
175
198
 
199
+ clickOutside(evt) {
200
+ if (this.state.subAreaDisplayed) {
201
+ const items = document.getElementsByClassName(this.generateActionName());
202
+ const isOver = items && items.length > 0 ? items[0].contains(evt.target) : false;
203
+
204
+ if (!isOver) {
205
+ this.closeSubArea();
206
+ }
207
+ }
208
+ }
209
+
210
+ openSubArea() {
211
+ this.setState({ subAreaDisplayed: true });
212
+ }
213
+
214
+ closeSubArea() {
215
+ this.setState({ subAreaDisplayed: false });
216
+ }
217
+
176
218
  actionClickHandler(evt) {
177
- if (!this.props.actionObj.subMenu && !this.props.actionObj.subPanel) {
219
+ if (this.props.actionObj.subMenu || this.props.actionObj.subPanel) {
220
+ if (this.state.showExtendedMenu) {
221
+ document.removeEventListener("click", this.clickOutside, false);
222
+ } else {
223
+ document.addEventListener("click", this.clickOutside, false);
224
+ }
225
+
226
+ if (this.props.setResizeHandler) {
227
+ if (this.state.subAreaDisplayed) {
228
+ this.props.setResizeHandler(null);
229
+ } else {
230
+ this.props.setResizeHandler(this.closeSubArea);
231
+ }
232
+ }
233
+
234
+ if (!this.props.overflow) {
235
+ this.setState({ subAreaDisplayed: !this.state.subAreaDisplayed });
236
+ }
237
+ } else {
178
238
  this.props.toolbarActionHandler(this.props.actionObj.action, evt);
179
239
  }
180
240
  }
@@ -204,10 +264,10 @@ class ToolbarActionItem extends React.Component {
204
264
  // If no 'kind' is set, use ghost and then override colors using the "default" class in innerDivClassName.
205
265
  const kind = actionObj.kind || "ghost";
206
266
 
207
- const chevronIcon = actionObj.subMenu || this.props.actionObj.subPanel ? (<ChevronRight16 />) : null;
267
+ const chevronIcon = this.generateChevronIcon(actionObj);
208
268
 
209
269
  let buttonContent = (
210
- <div className={itemContentClassName}>
270
+ <div id={"open-action-item"} className={itemContentClassName}>
211
271
  {labelBefore}
212
272
  {icon}
213
273
  {labelAfter}
@@ -237,6 +297,41 @@ class ToolbarActionItem extends React.Component {
237
297
  return buttonContent;
238
298
  }
239
299
 
300
+ // Returns a chevron icon if the action icon is displaying a sub-menu or
301
+ // sub-panel. The chevron will:
302
+ // * point right if this action item is in a drop down menu
303
+ // * point down if this action item is displayed with text in the toolbar
304
+ // and the menu isn't displayed
305
+ // * point up if this action item is displayed with text in the toolbar
306
+ // and the menu is displayed
307
+ // * be a mini-chevron (small triangle in the bottom right of icon) if this
308
+ // action item isn't displayed with text.
309
+ generateChevronIcon(actionObj) {
310
+ if (actionObj.subMenu || actionObj.subPanel) {
311
+ if (this.props.overflow) {
312
+ return (<ChevronRight16 />);
313
+ }
314
+ if (actionObj.incLabelWithIcon === "before" ||
315
+ actionObj.incLabelWithIcon === "after") {
316
+ const chev = this.state.subAreaDisplayed ? (<ChevronUp16 />) : (<ChevronDown16 />);
317
+ return (<div className={"toolbar-up-down-chevron"}>{chev}</div>);
318
+ }
319
+ return this.generateChevronMini();
320
+ }
321
+ return null;
322
+ }
323
+
324
+ // Returns an svg to display the little triangle that appears in the bottom
325
+ // right corner of icons that, when clicked, show a drop down menu.
326
+ generateChevronMini() {
327
+ const path = this.props.size === "sm" ? "M 29 29 L 29 23 23 29 Z" : "M 37 37 L 37 30 30 37 Z";
328
+ return (
329
+ <svg className="toolbar-tick-svg">
330
+ <path d={path} className="toolbar-tick-mark" />
331
+ </svg>
332
+ );
333
+ }
334
+
240
335
  generateActionName(actionObj) {
241
336
  return this.props.actionObj.action + "-action";
242
337
  }
@@ -277,34 +372,19 @@ class ToolbarActionItem extends React.Component {
277
372
  // supPanel field OR a sub-menu which is a list of options which is created
278
373
  // from the array of items the caller passes in the subMenu field.
279
374
  generateSubArea() {
280
- if (this.props.displaySubArea) {
281
- const style = this.calcSubAreaStyle();
282
-
283
- if (this.props.actionObj.subPanel) {
284
- return (
285
- <div style={style} className={"toolbar-popover-list subpanel"}>
286
- {this.props.actionObj.subPanel}
287
- </div>
288
- );
289
- }
290
- const subMenuItems = this.props.generateToolbarItems(this.props.actionObj.subMenu, true, false);
291
-
292
- return (
293
- <div style={style} className={"toolbar-popover-list submenu"}>
294
- {subMenuItems}
295
- </div>
296
- );
297
- }
298
-
299
- return null;
300
- }
375
+ const elements = document.getElementsByClassName(this.generateActionName());
376
+ const actionItemRect = elements && elements.length > 0 ? elements[0].getBoundingClientRect() : { top: 0, left: 0, width: 120 };
301
377
 
302
- calcSubAreaStyle() {
303
- const className = this.generateActionName();
304
- const elements = document.getElementsByClassName(className);
305
- const rect = elements && elements.length > 0 ? elements[0].getBoundingClientRect() : { top: 0, left: 0, width: 120 };
306
- const style = { top: rect.top - 1, left: rect.left + rect.width };
307
- return style;
378
+ return (
379
+ <ToolbarActionSubArea
380
+ actionObj={this.props.actionObj}
381
+ generateToolbarItems={this.props.generateToolbarItems}
382
+ closeSubArea={this.props.actionObj.closeSubAreaOnClick ? this.closeSubArea : null}
383
+ actionItemRect={actionItemRect}
384
+ containingDivId={this.props.containingDivId}
385
+ expandDirection={this.props.overflow ? "horizontal" : "vertical" }
386
+ />
387
+ );
308
388
  }
309
389
 
310
390
  render() {
@@ -330,7 +410,7 @@ class ToolbarActionItem extends React.Component {
330
410
  kindAsClass,
331
411
  actionName);
332
412
 
333
- const subArea = this.generateSubArea();
413
+ const subArea = this.state.subAreaDisplayed ? this.generateSubArea() : null;
334
414
 
335
415
  return (
336
416
  <div className={itemClassName} data-toolbar-item={isToolbarItem} onMouseEnter={this.onMouseEnter} onMouseLeave={this.onMouseLeave}>
@@ -362,6 +442,8 @@ ToolbarActionItem.propTypes = {
362
442
  textContent: PropTypes.string,
363
443
  isSelected: PropTypes.bool,
364
444
  kind: PropTypes.string,
445
+ closeSubAreaOnClick: PropTypes.bool,
446
+ getSubPanelCloseFn: PropTypes.func,
365
447
  subMenu: PropTypes.array,
366
448
  subPanel: PropTypes.object,
367
449
  jsx: PropTypes.object,
@@ -373,10 +455,10 @@ ToolbarActionItem.propTypes = {
373
455
  }),
374
456
  tooltipDirection: PropTypes.oneOf(["top", "bottom"]),
375
457
  toolbarActionHandler: PropTypes.func.isRequired,
376
- subMenuActionHandler: PropTypes.func.isRequired,
377
458
  generateToolbarItems: PropTypes.func.isRequired,
459
+ setResizeHandler: PropTypes.func,
378
460
  instanceId: PropTypes.number.isRequired,
379
- displaySubArea: PropTypes.bool,
461
+ containingDivId: PropTypes.string,
380
462
  overflow: PropTypes.bool,
381
463
  onFocus: PropTypes.func,
382
464
  size: PropTypes.oneOf(["md", "sm"])
@@ -0,0 +1,126 @@
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 { genElementByClass, genRectByClass } from "./toolbar-utils.js";
20
+
21
+ class ToolbarActionSubArea extends React.Component {
22
+ constructor(props) {
23
+ super(props);
24
+
25
+ this.onClick = this.onClick.bind(this);
26
+ }
27
+
28
+ componentDidMount() {
29
+ if (this.props.containingDivId) {
30
+ this.adjustSubAreaPosition();
31
+ }
32
+ }
33
+
34
+ // If we are given a closeSubArea function then call it. We will only have
35
+ // such a function if the user has specified the closeSubAreaOnClick prop for
36
+ // the parent action AND provided the user has not stopped event propogation.
37
+ onClick() {
38
+ if (this.props.closeSubArea) {
39
+ this.props.closeSubArea();
40
+ }
41
+ }
42
+
43
+ // Adjust the position of the sub-area to make sure it doesn't extend
44
+ // outside the containing divs boundary. We need to do this after the subarea
45
+ // has been mounted so we can query its size and position.
46
+ adjustSubAreaPosition() {
47
+ const containingDiv = document.getElementById(this.props.containingDivId);
48
+ const containingDivRect = containingDiv.getBoundingClientRect();
49
+
50
+ const classToGet = this.props.actionObj.subPanel ? "subpanel" : "submenu";
51
+
52
+ const thisArea = genElementByClass(classToGet, containingDiv);
53
+ const thisAreaRect = genRectByClass(classToGet, containingDiv);
54
+
55
+ const outsideBottom = thisAreaRect.bottom - containingDivRect.bottom;
56
+ const outsideRight = thisAreaRect.right - containingDivRect.right;
57
+
58
+ if (this.props.expandDirection === "vertical") {
59
+ if (outsideBottom > 0) {
60
+ const newTop = this.props.actionItemRect.top - thisAreaRect.height;
61
+ thisArea.style.top = newTop + "px";
62
+ }
63
+
64
+ if (outsideRight > 0) {
65
+ const newLeft = this.props.actionItemRect.left - outsideRight - 2;
66
+ thisArea.style.left = newLeft + "px";
67
+ }
68
+
69
+ } else {
70
+ if (outsideBottom > 0) {
71
+ const newTop = thisAreaRect.top - outsideBottom - 2;
72
+ thisArea.style.top = newTop + "px";
73
+ }
74
+
75
+ if (outsideRight > 0) {
76
+ const newLeft = this.props.actionItemRect.left - thisAreaRect.width;
77
+ thisArea.style.left = newLeft + "px";
78
+ }
79
+ }
80
+ }
81
+
82
+ generateSubAreaStyle() {
83
+ if (this.props.expandDirection === "vertical") {
84
+ return {
85
+ top: this.props.actionItemRect.bottom + 1,
86
+ left: this.props.actionItemRect.left
87
+ };
88
+ }
89
+ return {
90
+ top: this.props.actionItemRect.top - 1,
91
+ left: this.props.actionItemRect.left + this.props.actionItemRect.width
92
+ };
93
+ }
94
+
95
+ render() {
96
+ const style = this.generateSubAreaStyle();
97
+
98
+ if (this.props.actionObj.subPanel) {
99
+ return (
100
+ <div style={style} className={"toolbar-popover-list subpanel"} onClick={this.onClick}>
101
+ {this.props.actionObj.subPanel}
102
+ </div>
103
+ );
104
+ } else if (this.props.actionObj.subMenu) {
105
+ const subMenuItems = this.props.generateToolbarItems(this.props.actionObj.subMenu, true, false);
106
+
107
+ return (
108
+ <div style={style} className={"toolbar-popover-list submenu"} onClick={this.onClick}>
109
+ {subMenuItems}
110
+ </div>
111
+ );
112
+ }
113
+ return null;
114
+ }
115
+ }
116
+
117
+ ToolbarActionSubArea.propTypes = {
118
+ actionObj: PropTypes.object.isRequired,
119
+ generateToolbarItems: PropTypes.func.isRequired,
120
+ closeSubArea: PropTypes.func,
121
+ actionItemRect: PropTypes.object.isRequired,
122
+ expandDirection: PropTypes.string.isRequired,
123
+ containingDivId: PropTypes.string
124
+ };
125
+
126
+ export default ToolbarActionSubArea;
@@ -17,36 +17,83 @@
17
17
  import React from "react";
18
18
  import PropTypes from "prop-types";
19
19
 
20
+ import { v4 as uuid4 } from "uuid";
20
21
  import { Button } from "carbon-components-react";
21
22
  import { OverflowMenuVertical16 } from "@carbon/icons-react";
23
+ import ToolbarOverflowMenu from "./toolbar-overflow-menu.jsx";
22
24
 
23
25
  class ToolbarOverflowItem extends React.Component {
24
26
  constructor(props) {
25
27
  super(props);
28
+
29
+ this.state = {
30
+ showExtendedMenu: false
31
+ };
32
+ this.uuid = uuid4();
26
33
  this.toggleExtendedMenu = this.toggleExtendedMenu.bind(this);
34
+ this.clickOutside = this.clickOutside.bind(this);
35
+ }
36
+
37
+ // We must remove the eventListener in case this class is unmounted due
38
+ // to the toolbar getting redrawn.
39
+ componentWillUnmount() {
40
+ document.removeEventListener("click", this.clickOutside, false);
41
+ }
42
+
43
+ genOverflowButtonClass() {
44
+ return "toolbar-spacer toolbar-index-" + this.props.index + " toolbar-uuid-" + this.uuid;
27
45
  }
28
46
 
29
47
  toggleExtendedMenu() {
30
- this.props.toggleExtendedMenu(this.props.index);
48
+ if (this.state.showExtendedMenu) {
49
+ document.removeEventListener("click", this.clickOutside, false);
50
+ } else {
51
+ document.addEventListener("click", this.clickOutside, false);
52
+ }
53
+
54
+ if (this.props.setResizeHandler) {
55
+ if (this.state.showExtendedMenu) {
56
+ this.props.setResizeHandler(null);
57
+ } else {
58
+ this.props.setResizeHandler(() => {
59
+ this.setState({ showExtendedMenu: false });
60
+ });
61
+ }
62
+ }
63
+
64
+ this.setState({ showExtendedMenu: !this.state.showExtendedMenu });
65
+ }
66
+
67
+ clickOutside(evt) {
68
+ if (this.state.showExtendedMenu) {
69
+ const items = document.getElementsByClassName("toolbar-uuid-" + this.uuid);
70
+ const isOver = items && items.length > 0 ? items[0].contains(evt.target) : false;
71
+
72
+ if (!isOver) {
73
+ this.setState({ showExtendedMenu: false });
74
+ }
75
+ }
31
76
  }
32
77
 
33
78
  render() {
79
+ if (this.props.setResizeHandler && !this.state.showExtendedMenu) {
80
+ this.props.setResizeHandler(null);
81
+ }
82
+
34
83
  let overflowMenu = null;
35
- if (this.props.showExtendedMenu) {
84
+ if (this.state.showExtendedMenu) {
36
85
  const menuItems = this.props.generateExtensionMenuItems(this.props.index);
37
- if (menuItems.length > 0) {
38
- overflowMenu = (
39
- <div className={"toolbar-popover-list"}>
40
- {menuItems}
41
- </div>
42
- );
43
- }
86
+ overflowMenu = (
87
+ <ToolbarOverflowMenu
88
+ menuItems={menuItems}
89
+ containingDivId={this.props.containingDivId}
90
+ buttonClass={"toolbar-uuid-" + this.uuid}
91
+ />
92
+ );
44
93
  }
45
94
 
46
- const className = "toolbar-spacer toolbar-index-" + this.props.index;
47
-
48
95
  return (
49
- <div className={className} >
96
+ <div className={this.genOverflowButtonClass()} >
50
97
  <div className={"toolbar-overflow-item"}>
51
98
  <Button kind="ghost"
52
99
  tabIndex={-1}
@@ -69,10 +116,10 @@ class ToolbarOverflowItem extends React.Component {
69
116
  }
70
117
 
71
118
  ToolbarOverflowItem.propTypes = {
72
- showExtendedMenu: PropTypes.bool.isRequired,
73
- toggleExtendedMenu: PropTypes.func.isRequired,
74
119
  index: PropTypes.number.isRequired,
75
120
  generateExtensionMenuItems: PropTypes.func,
121
+ setResizeHandler: PropTypes.func,
122
+ containingDivId: PropTypes.string,
76
123
  onFocus: PropTypes.func,
77
124
  label: PropTypes.string,
78
125
  size: PropTypes.oneOf(["md", "sm"])
@@ -0,0 +1,77 @@
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
+ import { genElementByClass, genRectByClass } from "./toolbar-utils.js";
20
+
21
+ class ToolbarOverflowMenu extends React.Component {
22
+
23
+ componentDidMount() {
24
+ if (this.props.containingDivId) {
25
+ this.setSubAreaStyle();
26
+ }
27
+ }
28
+
29
+ setSubAreaStyle() {
30
+ const containingDiv = document.getElementById(this.props.containingDivId);
31
+ const containingDivRect = containingDiv.getBoundingClientRect();
32
+
33
+ const mainMenu = genElementByClass("toolbar-popover-list", containingDiv);
34
+ const mainMenuRect = genRectByClass("toolbar-popover-list", containingDiv);
35
+
36
+ if (mainMenuRect) {
37
+ const overflowButtonRect = genRectByClass(this.props.buttonClass, containingDiv);
38
+
39
+ if (overflowButtonRect) {
40
+ const contextToolbaRect = genRectByClass("context-toolbar", containingDiv);
41
+
42
+ if (contextToolbaRect) {
43
+ const outsideRight = mainMenuRect.right - containingDivRect.right;
44
+ if (outsideRight > 0) {
45
+ const overflowIconOffsetX = overflowButtonRect.left - contextToolbaRect.left;
46
+ mainMenu.style.left = (overflowIconOffsetX - outsideRight - 2) + "px";
47
+ }
48
+
49
+ const outsideBottom = mainMenuRect.bottom - containingDivRect.bottom;
50
+ if (outsideBottom > 0) {
51
+ mainMenu.style.top = -mainMenuRect.height + "px";
52
+ }
53
+ }
54
+ }
55
+ }
56
+ }
57
+
58
+ render() {
59
+ let overflowMenu = null;
60
+ if (this.props.menuItems.length > 0) {
61
+ overflowMenu = (
62
+ <div className={"toolbar-popover-list"}>
63
+ {this.props.menuItems}
64
+ </div>
65
+ );
66
+ }
67
+ return overflowMenu;
68
+ }
69
+ }
70
+
71
+ ToolbarOverflowMenu.propTypes = {
72
+ menuItems: PropTypes.array.isRequired,
73
+ containingDivId: PropTypes.string,
74
+ buttonClass: PropTypes.string
75
+ };
76
+
77
+ export default ToolbarOverflowMenu;
@@ -0,0 +1,33 @@
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
+ export const genElementByClass = (className, containingDiv) => {
18
+ const elements = containingDiv.getElementsByClassName(className);
19
+
20
+ if (elements && elements.length > 0) {
21
+ return elements[0];
22
+ }
23
+ return null;
24
+ };
25
+
26
+ export const genRectByClass = (className, containingDiv) => {
27
+ const element = genElementByClass(className, containingDiv);
28
+
29
+ if (element) {
30
+ return element.getBoundingClientRect();
31
+ }
32
+ return null;
33
+ };