@elyra/canvas 12.41.0 → 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 (150) 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-43e2d052.js → flexible-table-35e9922a.js} +2 -2
  28. package/dist/{flexible-table-43e2d052.js.map → flexible-table-35e9922a.js.map} +1 -1
  29. package/dist/{flexible-table-63ffd573.js → flexible-table-7c7de0f9.js} +1 -1
  30. package/dist/{flexible-table-63ffd573.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-57503b50.js → index-94fec521.js} +2 -2
  34. package/dist/{index-57503b50.js.map → index-94fec521.js.map} +1 -1
  35. package/dist/{index-1cd54914.js → index-e2f8a935.js} +2 -2
  36. package/dist/{index-1cd54914.js.map → index-e2f8a935.js.map} +1 -1
  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/package.json +12 -4
  62. package/src/color-picker/color-picker.jsx +92 -17
  63. package/src/command-actions/arrangeLayoutAction.js +7 -6
  64. package/src/command-actions/attachNodeToLinksAction.js +4 -4
  65. package/src/command-actions/collapseSuperNodeInPlaceAction.js +5 -5
  66. package/src/command-actions/colorSelectedObjectsAction.js +4 -4
  67. package/src/command-actions/commonPropertiesAction.js +1 -1
  68. package/src/command-actions/convertSuperNodeExternalToLocalAction.js +4 -4
  69. package/src/command-actions/convertSuperNodeLocalToExternalAction.js +4 -4
  70. package/src/command-actions/createAutoNodeAction.js +14 -5
  71. package/src/command-actions/createCommentAction.js +4 -10
  72. package/src/command-actions/createCommentLinkAction.js +4 -4
  73. package/src/command-actions/createNodeAction.js +13 -4
  74. package/src/command-actions/createNodeAttachLinksAction.js +4 -4
  75. package/src/command-actions/createNodeLinkAction.js +13 -4
  76. package/src/command-actions/createNodeLinkDetachedAction.js +4 -4
  77. package/src/command-actions/createNodeOnLinkAction.js +4 -4
  78. package/src/command-actions/createSuperNodeAction.js +7 -7
  79. package/src/command-actions/deconstructSuperNodeAction.js +5 -5
  80. package/src/command-actions/deleteLinkAction.js +4 -4
  81. package/src/command-actions/deleteObjectsAction.js +15 -6
  82. package/src/command-actions/disconnectObjectsAction.js +13 -4
  83. package/src/command-actions/displayPreviousPipelineAction.js +4 -4
  84. package/src/command-actions/displaySubPipelineAction.js +4 -4
  85. package/src/command-actions/editCommentAction.js +4 -4
  86. package/src/command-actions/editDecorationLabelAction.js +4 -4
  87. package/src/command-actions/expandSuperNodeInPlaceAction.js +5 -5
  88. package/src/command-actions/insertNodeIntoLinkAction.js +4 -4
  89. package/src/command-actions/moveObjectsAction.js +4 -4
  90. package/src/command-actions/pasteAction.js +16 -7
  91. package/src/command-actions/saveToPaletteAction.js +4 -4
  92. package/src/command-actions/setLinksStyleAction.js +4 -4
  93. package/src/command-actions/setNodeLabelAction.js +4 -4
  94. package/src/command-actions/setObjectsStyleAction.js +4 -4
  95. package/src/command-actions/sizeAndPositionObjectsAction.js +4 -4
  96. package/src/command-actions/updateLinkAction.js +4 -4
  97. package/src/common-canvas/canvas-controller-menu-utils.js +1 -1
  98. package/src/common-canvas/canvas-controller.js +78 -62
  99. package/src/common-canvas/cc-central-items.jsx +1 -1
  100. package/src/common-canvas/cc-context-toolbar.jsx +9 -13
  101. package/src/common-canvas/cc-toolbar.jsx +2 -0
  102. package/src/common-canvas/svg-canvas-renderer.js +6 -2
  103. package/src/common-canvas/svg-canvas-utils-drag-det-link.js +8 -1
  104. package/src/common-canvas/svg-canvas-utils-drag-new-link.js +1 -1
  105. package/src/common-properties/components/table-buttons/table-buttons.scss +0 -1
  106. package/src/common-properties/controls/expression/expression-builder/expression-builder.jsx +32 -26
  107. package/src/common-properties/controls/expression/expression.jsx +146 -117
  108. package/src/common-properties/controls/expression/expression.scss +43 -45
  109. package/src/common-properties/controls/expression/languages/CLEM-hint.js +86 -159
  110. package/src/common-properties/controls/expression/languages/python-hint.js +53 -104
  111. package/src/common-properties/controls/expression/languages/r-hint.js +55 -130
  112. package/src/common-properties/properties-controller.js +5 -0
  113. package/src/context-menu/common-context-menu.jsx +4 -1
  114. package/src/index.js +12 -2
  115. package/src/object-model/redux/canvas-store.js +4 -3
  116. package/src/toolbar/toolbar-action-item.jsx +90 -314
  117. package/src/toolbar/toolbar-button-item.jsx +354 -0
  118. package/src/toolbar/toolbar-divider-item.jsx +3 -4
  119. package/src/toolbar/toolbar-overflow-item.jsx +82 -36
  120. package/src/toolbar/toolbar-sub-menu-item.jsx +235 -0
  121. package/src/toolbar/toolbar-sub-menu.jsx +254 -0
  122. package/src/toolbar/toolbar-sub-panel.jsx +81 -0
  123. package/src/toolbar/toolbar-sub-utils.js +77 -0
  124. package/src/toolbar/toolbar.jsx +330 -146
  125. package/src/toolbar/toolbar.scss +22 -15
  126. package/src/tooltip/tooltip.jsx +9 -2
  127. package/stats.html +1 -1
  128. package/dist/canvas-controller-1e71b405.js +0 -2
  129. package/dist/canvas-controller-1e71b405.js.map +0 -1
  130. package/dist/canvas-controller-4bed5320.js +0 -2
  131. package/dist/canvas-controller-4bed5320.js.map +0 -1
  132. package/dist/common-canvas-097c5169.js +0 -2
  133. package/dist/common-canvas-097c5169.js.map +0 -1
  134. package/dist/common-canvas-e13c0858.js +0 -2
  135. package/dist/common-canvas-e13c0858.js.map +0 -1
  136. package/dist/common-properties-706cef87.js +0 -2
  137. package/dist/common-properties-706cef87.js.map +0 -1
  138. package/dist/common-properties-9bd69b61.js +0 -2
  139. package/dist/common-properties-9bd69b61.js.map +0 -1
  140. package/dist/context-menu-wrapper-3a7fdec8.js +0 -2
  141. package/dist/context-menu-wrapper-3a7fdec8.js.map +0 -1
  142. package/dist/context-menu-wrapper-fc85d853.js +0 -2
  143. package/dist/context-menu-wrapper-fc85d853.js.map +0 -1
  144. package/dist/toolbar-918ab52e.js +0 -2
  145. package/dist/toolbar-918ab52e.js.map +0 -1
  146. package/dist/toolbar-fdb750f9.js +0 -2
  147. package/dist/toolbar-fdb750f9.js.map +0 -1
  148. package/src/toolbar/toolbar-action-sub-area.jsx +0 -126
  149. package/src/toolbar/toolbar-overflow-menu.jsx +0 -77
  150. package/src/toolbar/toolbar-utils.js +0 -33
@@ -0,0 +1,354 @@
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 Tooltip from "../tooltip/tooltip.jsx";
21
+ import ArrangeHorizontally from "./../../assets/images/arrange_horizontally.svg";
22
+ import ArrangeVertically from "./../../assets/images/arrange_vertically.svg";
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
+
28
+ import { Button } from "carbon-components-react";
29
+ import SVG from "react-inlinesvg";
30
+ import classNames from "classnames";
31
+ import { StopFilledAlt16, Play16, Undo16, Redo16, Chat16, ChatOff16, Result16,
32
+ Cut16, Copy16, Paste16, Edit16, ColorPalette16, Maximize16, Minimize16,
33
+ Launch16, AddComment16, TrashCan16, ZoomIn16, ZoomOut16,
34
+ ChevronRight16, ChevronDown16, ChevronUp16 } from "@carbon/icons-react";
35
+ import { TOOLBAR_STOP, TOOLBAR_RUN, TOOLBAR_UNDO, TOOLBAR_REDO,
36
+ TOOLBAR_CUT, TOOLBAR_COPY, TOOLBAR_PASTE, TOOLBAR_CLIPBOARD,
37
+ TOOLBAR_CREATE_COMMENT, TOOLBAR_CREATE_AUTO_COMMENT, TOOLBAR_COLOR_BACKGROUND,
38
+ TOOLBAR_DELETE_SELECTED_OBJECTS, TOOLBAR_DELETE_LINK,
39
+ TOOLBAR_ZOOM_IN, TOOLBAR_ZOOM_OUT, TOOLBAR_ZOOM_FIT,
40
+ TOOLBAR_ARRANGE_HORIZONALLY, TOOLBAR_ARRANGE_VERTICALLY,
41
+ TOOLBAR_OPEN_PALETTE, TOOLBAR_CLOSE_PALETTE, TOOLBAR_TOGGLE_NOTIFICATION_PANEL,
42
+ TOOLBAR_SHOW_COMMENTS, TOOLBAR_HIDE_COMMENTS,
43
+ TOOLBAR_EXPAND_SUPERNODE_IN_PLACE, TOOLBAR_COLLAPSE_SUPERNODE_IN_PLACE,
44
+ TOOLBAR_EXPAND_SUPERNODE_FULL_PAGE, TOOLBAR_SET_NODE_LABEL_EDIT, TOOLBAR_SET_COMMENT_EDIT_MODE }
45
+ from "../common-canvas/constants/canvas-constants.js";
46
+
47
+ class ToolbarButtonItem extends React.Component {
48
+ constructor(props) {
49
+ super(props);
50
+
51
+ this.buttonRef = React.createRef();
52
+ }
53
+
54
+ componentDidUpdate() {
55
+ if (this.props.isFocusInToolbar &&
56
+ this.props.buttonFocusAction === this.props.actionObj.action) {
57
+ this.buttonRef.current.focus();
58
+ }
59
+ }
60
+
61
+ // Returns a default icon, if there is one, for the action passed in.
62
+ // It also may be set to disabled state.
63
+ getDefaultIcon(actionObj) {
64
+ const disabled = !actionObj.enable;
65
+
66
+ switch (actionObj.action) {
67
+ case (TOOLBAR_STOP):
68
+ return <StopFilledAlt16 disabled={disabled} />;
69
+ case (TOOLBAR_RUN):
70
+ return <Play16 disabled={disabled} />;
71
+ case (TOOLBAR_EXPAND_SUPERNODE_IN_PLACE):
72
+ return <Maximize16 disabled={disabled} />;
73
+ case (TOOLBAR_COLLAPSE_SUPERNODE_IN_PLACE):
74
+ return <Minimize16 disabled={disabled} />;
75
+ case (TOOLBAR_EXPAND_SUPERNODE_FULL_PAGE):
76
+ return <Launch16 disabled={disabled} />;
77
+ case (TOOLBAR_UNDO):
78
+ return <Undo16 disabled={disabled} />;
79
+ case (TOOLBAR_REDO):
80
+ return <Redo16 disabled={disabled} />;
81
+ case (TOOLBAR_CLIPBOARD):
82
+ return <Result16 disabled={disabled} />;
83
+ case (TOOLBAR_CUT):
84
+ return <Cut16 disabled={disabled} />;
85
+ case (TOOLBAR_COPY):
86
+ return <Copy16 disabled={disabled} />;
87
+ case (TOOLBAR_PASTE):
88
+ return <Paste16 disabled={disabled} />;
89
+ case (TOOLBAR_CREATE_COMMENT):
90
+ case (TOOLBAR_CREATE_AUTO_COMMENT):
91
+ return <AddComment16 disabled={disabled} />;
92
+ case (TOOLBAR_SHOW_COMMENTS):
93
+ return <Chat16 disabled={disabled} />;
94
+ case (TOOLBAR_HIDE_COMMENTS):
95
+ return <ChatOff16 disabled={disabled} />;
96
+ case (TOOLBAR_COLOR_BACKGROUND):
97
+ return <ColorPalette16 disabled={disabled} />;
98
+ case (TOOLBAR_DELETE_LINK):
99
+ case (TOOLBAR_DELETE_SELECTED_OBJECTS):
100
+ return <TrashCan16 disabled={disabled} />;
101
+ case (TOOLBAR_SET_COMMENT_EDIT_MODE):
102
+ case (TOOLBAR_SET_NODE_LABEL_EDIT):
103
+ return <Edit16 disabled={disabled} />;
104
+ case (TOOLBAR_ZOOM_IN):
105
+ return <ZoomIn16 disabled={disabled} />;
106
+ case (TOOLBAR_ZOOM_OUT):
107
+ return <ZoomOut16 disabled={disabled} />;
108
+
109
+ case (TOOLBAR_ZOOM_FIT):
110
+ return <SVG src={ZoomToFit} disabled={disabled} />;
111
+ case (TOOLBAR_ARRANGE_HORIZONALLY):
112
+ return <SVG src={ArrangeHorizontally} disabled={disabled} />;
113
+ case (TOOLBAR_ARRANGE_VERTICALLY):
114
+ 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
+ case (TOOLBAR_TOGGLE_NOTIFICATION_PANEL):
120
+ return <SVG src={ToggleNotificationPanel} disabled={disabled} />;
121
+
122
+ default:
123
+ return null;
124
+ }
125
+ }
126
+
127
+ generateLabel(label, disable, isInMenu, incLabelWithIcon) {
128
+ let className = "toolbar-icon-label";
129
+ className += this.generateLabelType(isInMenu, incLabelWithIcon);
130
+ className += disable ? " disabled" : "";
131
+ return (<div className={className}>{label}</div>);
132
+ }
133
+
134
+ generateLabelType(isInMenu, inLabelWithIcon) {
135
+ if (isInMenu) {
136
+ return " overflow";
137
+ } else if (inLabelWithIcon === "before") {
138
+ return " before";
139
+ } else if (inLabelWithIcon === "after") {
140
+ return " after";
141
+ }
142
+ return "";
143
+ }
144
+
145
+ generateIcon(actionObj) {
146
+ let icon = this.getDefaultIcon(actionObj);
147
+
148
+ // Host application provided icon. This will override any default icon.
149
+ if (actionObj.iconEnabled) {
150
+ const iconEnabled = actionObj.iconEnabled;
151
+ const iconDisabled = actionObj.iconDisabled || actionObj.iconEnabled;
152
+ const customIcon = actionObj.enable ? iconEnabled : iconDisabled;
153
+ const id = "toolbar-icon-" + this.props.instanceId + " -" + actionObj.action;
154
+
155
+ if (typeof customIcon === "string") {
156
+ icon = (<SVG id={id} src={customIcon} disabled={!actionObj.enable} />);
157
+ } else {
158
+ icon = customIcon;
159
+ }
160
+ }
161
+
162
+ if (icon) {
163
+ return (
164
+ <div className={"toolbar-icon"}>
165
+ {icon}
166
+ </div>
167
+ );
168
+ }
169
+ return null;
170
+ }
171
+
172
+ generateButton(actionObj) {
173
+ let labelBefore = null;
174
+ let labelAfter = null;
175
+
176
+ if (this.props.isInMenu) {
177
+ labelAfter = this.generateLabel(actionObj.label, !actionObj.enable, true);
178
+
179
+ } else if (actionObj.incLabelWithIcon === "before") {
180
+ labelBefore = this.generateLabel(actionObj.label, !actionObj.enable, false, actionObj.incLabelWithIcon);
181
+
182
+ } else if (actionObj.incLabelWithIcon === "after") {
183
+ labelAfter = this.generateLabel(actionObj.label, !actionObj.enable, false, actionObj.incLabelWithIcon);
184
+ }
185
+
186
+ const icon = this.generateIcon(actionObj);
187
+ const textContent = actionObj.textContent ? (<div className="toolbar-text-content"> {actionObj.textContent} </div>) : null;
188
+
189
+ const itemContentClassName = classNames(
190
+ "toolbar-item-content",
191
+ actionObj.className ? actionObj.className : null,
192
+ { "overflow": this.props.isInMenu, "disabled": !actionObj.enable, "default": !actionObj.kind });
193
+
194
+ // If no 'kind' is set, use ghost and then override colors using the "default" class in innerDivClassName.
195
+ const kind = actionObj.kind || "ghost";
196
+
197
+ const chevronIcon = this.generateChevronIcon(actionObj);
198
+
199
+ let buttonContent = (
200
+ <div className={itemContentClassName}>
201
+ {labelBefore}
202
+ {icon}
203
+ {labelAfter}
204
+ {textContent}
205
+ {chevronIcon}
206
+ </div>
207
+ );
208
+
209
+ buttonContent = this.wrapInTooltip(buttonContent);
210
+
211
+ // Only specify an aria label for the button if a label is not displayed
212
+ // with the button icon.
213
+ const ariaLabel = actionObj.incLabelWithIcon ? null : actionObj.label;
214
+ const tabIndex = this.props.buttonFocusAction === actionObj.action ? 0 : -1;
215
+
216
+ const button = (
217
+ <Button kind={kind}
218
+ ref={this.buttonRef}
219
+ onClick={this.props.actionClickHandler}
220
+ disabled={!actionObj.enable}
221
+ aria-label={ariaLabel}
222
+ size={this.props.size}
223
+ tabIndex={tabIndex}
224
+ >
225
+ {buttonContent}
226
+ </Button>
227
+ );
228
+
229
+ return button;
230
+ }
231
+
232
+ // Returns a chevron icon if the action icon is displaying a sub-menu or
233
+ // sub-panel. The chevron will:
234
+ // * point right if this action item is in a drop down menu
235
+ // * point down if this action item is displayed with text in the toolbar
236
+ // and the menu isn't displayed
237
+ // * point up if this action item is displayed with text in the toolbar
238
+ // and the menu is displayed
239
+ // * be a mini-chevron (small triangle in the bottom right of icon) if this
240
+ // action item isn't displayed with text.
241
+ generateChevronIcon(actionObj) {
242
+ if (actionObj.subMenu || actionObj.subPanel) {
243
+ if (this.props.isInMenu) {
244
+ return (<ChevronRight16 />);
245
+ }
246
+ if (actionObj.incLabelWithIcon === "before" ||
247
+ actionObj.incLabelWithIcon === "after") {
248
+ const chev = this.props.subAreaDisplayed ? (<ChevronUp16 />) : (<ChevronDown16 />);
249
+ return (<div className={"toolbar-up-down-chevron"}>{chev}</div>);
250
+ }
251
+ return this.generateChevronMini();
252
+ }
253
+ return null;
254
+ }
255
+
256
+ // Returns an svg to display the little triangle that appears in the bottom
257
+ // right corner of icons that, when clicked, show a drop down menu.
258
+ generateChevronMini() {
259
+ const path = this.props.size === "sm" ? "M 29 29 L 29 23 23 29 Z" : "M 37 37 L 37 30 30 37 Z";
260
+ return (
261
+ <svg className="toolbar-tick-svg">
262
+ <path d={path} className="toolbar-tick-mark" />
263
+ </svg>
264
+ );
265
+ }
266
+
267
+ wrapInTooltip(content) {
268
+ if (!this.props.isInMenu && (this.showLabelAsTip(this.props.actionObj) || this.props.actionObj.tooltip)) {
269
+ const tip = this.props.actionObj.tooltip ? this.props.actionObj.tooltip : this.props.actionObj.label;
270
+ const tooltipId = this.props.actionName + "-" + this.props.instanceId + "-tooltip";
271
+ const enableTooltip = this.props.actionObj.enable || this.props.actionObj.jsx; // JSX 'tools' don't have enable attr so always display a tooltip for them.
272
+ const direction = this.props.tooltipDirection ? this.props.tooltipDirection : "bottom";
273
+
274
+ return (
275
+ <Tooltip id={tooltipId} tip={tip} disable={!enableTooltip} className="icon-tooltip" direction={direction}>
276
+ {content}
277
+ </Tooltip>
278
+ );
279
+ }
280
+ return content;
281
+ }
282
+
283
+ // Returns true if the label should be shown as a tooltip or false if not.
284
+ // We do not show the label as a tooltip if it is already shown in the
285
+ // toolbar next to the icon (i.e. incLabelWithIcon is set to something).
286
+ showLabelAsTip(actionObj) {
287
+ if (actionObj.label) {
288
+ if (actionObj.incLabelWithIcon === "before" ||
289
+ actionObj.incLabelWithIcon === "after") {
290
+ return false;
291
+ }
292
+ return true;
293
+ }
294
+ return false;
295
+ }
296
+
297
+ render() {
298
+ const actionObj = this.props.actionObj;
299
+ let divContent = null;
300
+
301
+ if (actionObj.jsx) {
302
+ divContent = this.wrapInTooltip(actionObj.jsx);
303
+ } else {
304
+ divContent = this.generateButton(actionObj);
305
+ }
306
+
307
+ return divContent;
308
+ }
309
+ }
310
+
311
+ ToolbarButtonItem.propTypes = {
312
+ actionObj: PropTypes.shape({
313
+ action: PropTypes.string.isRequired,
314
+ label: PropTypes.oneOfType([
315
+ PropTypes.string,
316
+ PropTypes.object
317
+ ]),
318
+ incLabelWithIcon: PropTypes.oneOf(["no", "before", "after"]),
319
+ enable: PropTypes.bool,
320
+ iconEnabled: PropTypes.oneOfType([
321
+ PropTypes.string,
322
+ PropTypes.object
323
+ ]),
324
+ iconDisabled: PropTypes.oneOfType([
325
+ PropTypes.string,
326
+ PropTypes.object
327
+ ]),
328
+ className: PropTypes.string,
329
+ textContent: PropTypes.string,
330
+ isSelected: PropTypes.bool,
331
+ kind: PropTypes.string,
332
+ closeSubAreaOnClick: PropTypes.bool,
333
+ subMenu: PropTypes.array,
334
+ subPanel: PropTypes.any,
335
+ subPanelData: PropTypes.object,
336
+ jsx: PropTypes.object,
337
+ tooltip: PropTypes.oneOfType([
338
+ PropTypes.string,
339
+ PropTypes.object,
340
+ PropTypes.func
341
+ ])
342
+ }),
343
+ actionName: PropTypes.string.isRequired,
344
+ tooltipDirection: PropTypes.oneOf(["top", "bottom"]),
345
+ instanceId: PropTypes.number.isRequired,
346
+ isInMenu: PropTypes.bool,
347
+ subAreaDisplayed: PropTypes.bool,
348
+ actionClickHandler: PropTypes.func,
349
+ buttonFocusAction: PropTypes.string,
350
+ isFocusInToolbar: PropTypes.bool,
351
+ size: PropTypes.oneOf(["md", "sm"])
352
+ };
353
+
354
+ export default ToolbarButtonItem;
@@ -18,21 +18,20 @@ import React from "react";
18
18
  import PropTypes from "prop-types";
19
19
 
20
20
  class ToolbarDividerItem extends React.Component {
21
-
22
21
  render() {
23
- const dividerClassName = this.props.overflow ? "toolbar-divider-overflow" : "toolbar-divider";
22
+ const dividerClassName = this.props.isInMenu ? "toolbar-divider-overflow" : "toolbar-divider";
24
23
 
25
24
  // Add a space as content. When using display: inline-block the div needs
26
25
  // some content so it is displayed inline with the other elements of the
27
26
  // toolbar. With no content it is displayed above (!) the other elements.
28
27
  return (
29
- <div className={dividerClassName} data-toolbar-item tabIndex={-1} aria-hidden >&nbsp;</div>
28
+ <div className={dividerClassName} tabIndex={-1} aria-hidden >&nbsp;</div>
30
29
  );
31
30
  }
32
31
  }
33
32
 
34
33
  ToolbarDividerItem.propTypes = {
35
- overflow: PropTypes.bool
34
+ isInMenu: PropTypes.bool
36
35
  };
37
36
 
38
37
  export default ToolbarDividerItem;
@@ -20,7 +20,7 @@ import PropTypes from "prop-types";
20
20
  import { v4 as uuid4 } from "uuid";
21
21
  import { Button } from "carbon-components-react";
22
22
  import { OverflowMenuVertical16 } from "@carbon/icons-react";
23
- import ToolbarOverflowMenu from "./toolbar-overflow-menu.jsx";
23
+ import ToolbarSubMenu from "./toolbar-sub-menu.jsx";
24
24
 
25
25
  class ToolbarOverflowItem extends React.Component {
26
26
  constructor(props) {
@@ -29,9 +29,19 @@ class ToolbarOverflowItem extends React.Component {
29
29
  this.state = {
30
30
  showExtendedMenu: false
31
31
  };
32
+
33
+ this.buttonRef = React.createRef();
34
+
32
35
  this.uuid = uuid4();
33
36
  this.toggleExtendedMenu = this.toggleExtendedMenu.bind(this);
34
37
  this.clickOutside = this.clickOutside.bind(this);
38
+ this.closeSubMenu = this.closeSubMenu.bind(this);
39
+ }
40
+
41
+ componentDidUpdate() {
42
+ if (this.props.toolbarFocusAction === this.props.action && this.props.isFocusInToolbar && !this.state.showExtendedMenu) {
43
+ this.buttonRef.current.focus();
44
+ }
35
45
  }
36
46
 
37
47
  // We must remove the eventListener in case this class is unmounted due
@@ -40,65 +50,96 @@ class ToolbarOverflowItem extends React.Component {
40
50
  document.removeEventListener("click", this.clickOutside, false);
41
51
  }
42
52
 
43
- genOverflowButtonClass() {
44
- return "toolbar-spacer toolbar-index-" + this.props.index + " toolbar-uuid-" + this.uuid;
53
+ // Called by toolbar.jsx
54
+ getAction() {
55
+ return this.props.action;
56
+ }
57
+
58
+ closeSubMenu() {
59
+ this.setState({ showExtendedMenu: false });
60
+ }
61
+
62
+ openSubMenu() {
63
+ this.setState({ showExtendedMenu: true });
64
+ }
65
+
66
+ genOverflowButtonClassName() {
67
+ return "toolbar-overflow-container " + this.genIndexClassName() + " " + this.genUuidClassName();
68
+ }
69
+
70
+ genIndexClassName() {
71
+ return "toolbar-index-" + this.props.index;
45
72
  }
46
73
 
74
+ genUuidClassName() {
75
+ return "toolbar-uuid-" + this.uuid;
76
+ }
77
+
78
+ // When the overflow item is clicked to open the overflow menu we must set the
79
+ // index of the overflow items so the overflow menu can be correctly constructed.
80
+ // The overflow index values are used to split out the overflow menu action items
81
+ // from the left bar and right bar.
82
+ // When the overflow menu is closed we set the overflow index values to null.
47
83
  toggleExtendedMenu() {
48
84
  if (this.state.showExtendedMenu) {
49
85
  document.removeEventListener("click", this.clickOutside, false);
86
+ this.props.setOverflowIndex(null); // Clear the indexes
87
+ this.closeSubMenu();
88
+ this.props.setToolbarFocusAction(this.props.action); // This will not set focus on this item
89
+
50
90
  } else {
51
91
  document.addEventListener("click", this.clickOutside, false);
92
+ this.props.setOverflowIndex(this.props.index);
93
+ this.openSubMenu();
94
+ this.props.setToolbarFocusAction(this.props.action);
52
95
  }
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
96
  }
66
97
 
67
98
  clickOutside(evt) {
68
99
  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) {
100
+ // Selector for the overflow-container that contains the overflow icon
101
+ // and submenu (if submenu is open).
102
+ const selector = "." + this.genIndexClassName();
103
+ const isClickInOverflowContainer = evt.target.closest(selector);
104
+ if (!isClickInOverflowContainer) {
73
105
  this.setState({ showExtendedMenu: false });
74
106
  }
75
107
  }
76
108
  }
77
109
 
78
110
  render() {
79
- if (this.props.setResizeHandler && !this.state.showExtendedMenu) {
80
- this.props.setResizeHandler(null);
81
- }
82
-
83
111
  let overflowMenu = null;
84
112
  if (this.state.showExtendedMenu) {
85
- const menuItems = this.props.generateExtensionMenuItems(this.props.index);
113
+ const actionItemRect = this.buttonRef.current.getBoundingClientRect();
86
114
  overflowMenu = (
87
- <ToolbarOverflowMenu
88
- menuItems={menuItems}
115
+ <ToolbarSubMenu
116
+ ref={this.subMenuRef}
117
+ subMenuActions={this.props.subMenuActions}
118
+ instanceId={this.props.instanceId}
119
+ toolbarActionHandler={this.props.toolbarActionHandler}
120
+ closeSubArea={this.closeSubMenu}
121
+ setToolbarFocusAction={this.props.setToolbarFocusAction}
122
+ actionItemRect={actionItemRect}
123
+ expandDirection={"vertical"}
89
124
  containingDivId={this.props.containingDivId}
90
- buttonClass={"toolbar-uuid-" + this.uuid}
125
+ parentSelector={".toolbar-overflow-container"}
126
+ isOverflowMenu
127
+ isCascadeMenu={false}
128
+ size={this.props.size}
91
129
  />
92
130
  );
93
131
  }
94
132
 
133
+ const tabIndex = this.props.toolbarFocusAction === this.props.action ? 0 : -1;
134
+
95
135
  return (
96
- <div className={this.genOverflowButtonClass()} >
136
+ <div className={this.genOverflowButtonClassName()} data-toolbar-action={this.props.action}>
97
137
  <div className={"toolbar-overflow-item"}>
98
- <Button kind="ghost"
99
- tabIndex={-1}
138
+ <Button
139
+ ref={this.buttonRef}
140
+ kind="ghost"
141
+ tabIndex={tabIndex}
100
142
  onClick={this.toggleExtendedMenu}
101
- onFocus={this.props.onFocus}
102
143
  aria-label={this.props.label}
103
144
  size={this.props.size}
104
145
  >
@@ -117,12 +158,17 @@ class ToolbarOverflowItem extends React.Component {
117
158
 
118
159
  ToolbarOverflowItem.propTypes = {
119
160
  index: PropTypes.number.isRequired,
120
- generateExtensionMenuItems: PropTypes.func,
121
- setResizeHandler: PropTypes.func,
122
- containingDivId: PropTypes.string,
123
- onFocus: PropTypes.func,
161
+ action: PropTypes.string,
124
162
  label: PropTypes.string,
125
- size: PropTypes.oneOf(["md", "sm"])
163
+ size: PropTypes.oneOf(["md", "sm"]),
164
+ subMenuActions: PropTypes.array,
165
+ setOverflowIndex: PropTypes.func,
166
+ toolbarActionHandler: PropTypes.func,
167
+ instanceId: PropTypes.number.isRequired,
168
+ containingDivId: PropTypes.string,
169
+ toolbarFocusAction: PropTypes.string,
170
+ setToolbarFocusAction: PropTypes.func,
171
+ isFocusInToolbar: PropTypes.bool
126
172
  };
127
173
 
128
174
  export default ToolbarOverflowItem;