diff --git a/canvas_modules/common-canvas/__tests__/common-canvas/common-canvas-text-toolbar-test.js b/canvas_modules/common-canvas/__tests__/common-canvas/common-canvas-text-toolbar-test.js index 1fe2027c5d..4693f3b2e1 100644 --- a/canvas_modules/common-canvas/__tests__/common-canvas/common-canvas-text-toolbar-test.js +++ b/canvas_modules/common-canvas/__tests__/common-canvas/common-canvas-text-toolbar-test.js @@ -39,7 +39,7 @@ describe("Common Canvas Text Toolbar renders correctly", () => { it("should render inside when open", () => { wrapper = createIntlCommonCanvasTextToolbar({}, canvasController); - canvasController.openTextToolbar(100, 200, MARKDOWN, () => { /**/ }); + canvasController.openTextToolbar(100, 200, [], MARKDOWN, () => { /**/ }); wrapper.update(); expect(wrapper.find(CommonCanvasTextToolbar)).to.have.length(1); @@ -63,7 +63,7 @@ describe("Common Canvas Text Toolbar renders correctly", () => { it("should render text toolbar in new position when moved", () => { wrapper = createIntlCommonCanvasTextToolbar({}, canvasController); - canvasController.openTextToolbar(100, 200, () => { /**/ }); + canvasController.openTextToolbar(100, 200, [], () => { /**/ }); wrapper.update(); expect(wrapper.find(".text-toolbar").get(0).props.style.left).to.equal(100); @@ -78,7 +78,7 @@ describe("Common Canvas Text Toolbar renders correctly", () => { it("should NOT render after it is closed", () => { wrapper = createIntlCommonCanvasTextToolbar({}, canvasController); - canvasController.openTextToolbar(100, 200, () => { /**/ }); + canvasController.openTextToolbar(100, 200, [], () => { /**/ }); wrapper.update(); expect(wrapper.find(CommonCanvasTextToolbar)).to.have.length(1); diff --git a/canvas_modules/common-canvas/src/color-picker/color-picker.jsx b/canvas_modules/common-canvas/src/color-picker/color-picker.jsx index 2d63d62170..8dfa84c44e 100644 --- a/canvas_modules/common-canvas/src/color-picker/color-picker.jsx +++ b/canvas_modules/common-canvas/src/color-picker/color-picker.jsx @@ -1,5 +1,5 @@ /* - * Copyright 2017-2023 Elyra Authors + * Copyright 2017-2024 Elyra Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -123,11 +123,17 @@ class ColorPicker extends React.Component { render() { this.logger.log("render"); if (this.props.subPanelData.type === WYSIWYG) { - const colorDivs = colorSetArray.map((c, i) => - (
{ + let className = "color-picker-item" + (c === "transparent" ? " color-transparent" : ""); + className += this.props.subPanelData.selectedColor === c ? " selected" : ""; + + return (
)); + className={className} + />); + }); const rowCount = Math.ceil(this.totalColors / this.colorsPerRow); diff --git a/canvas_modules/common-canvas/src/color-picker/color-picker.scss b/canvas_modules/common-canvas/src/color-picker/color-picker.scss index 3f822a3d6b..d84c365f1f 100644 --- a/canvas_modules/common-canvas/src/color-picker/color-picker.scss +++ b/canvas_modules/common-canvas/src/color-picker/color-picker.scss @@ -1,5 +1,5 @@ /* - * Copyright 2017-2023 Elyra Authors + * Copyright 2017-2024 Elyra Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -49,6 +49,10 @@ background: linear-gradient(to top left, $icon-inverse calc(50% - 1.2px), $icon-primary 50%, $icon-inverse calc(50% + 1.2px), $icon-inverse 100%); } + + &.selected { + outline: solid $layer-selected-inverse 2px; + } } } diff --git a/canvas_modules/common-canvas/src/common-canvas/canvas-controller.js b/canvas_modules/common-canvas/src/common-canvas/canvas-controller.js index 41f7ae362e..7ed3edf1ea 100644 --- a/canvas_modules/common-canvas/src/common-canvas/canvas-controller.js +++ b/canvas_modules/common-canvas/src/common-canvas/canvas-controller.js @@ -59,6 +59,8 @@ import { LINK_SELECTION_NONE, LINK_SELECTION_DETACHABLE, SNAP_TO_GRID_NONE, SUPER_NODE, WYSIWYG } from "./constants/canvas-constants"; +import { cloneDeep } from "lodash"; + // Global instance ID counter var commonCanvasControllerInstanceId = 0; @@ -2065,8 +2067,8 @@ export default class CanvasController { } } - openTextToolbar(xPos, yPos, contentType, actionHandler, blurHandler) { - this.objectModel.setTextToolbarDef({ isOpen: true, pos_x: xPos, pos_y: yPos, contentType, actionHandler, blurHandler }); + openTextToolbar(xPos, yPos, formats, contentType, actionHandler, blurHandler) { + this.objectModel.setTextToolbarDef({ isOpen: true, pos_x: xPos, pos_y: yPos, formats, contentType, actionHandler, blurHandler }); } closeTextToolbar() { @@ -2077,6 +2079,10 @@ export default class CanvasController { this.objectModel.setTextToolbarDef({ pos_x: xPos, pos_y: yPos }); } + updateTextToolbarFormats(formats) { + this.objectModel.setTextToolbarDef({ formats: cloneDeep(formats) }); // Clone to force mapToState refresh. + } + // Processes the drop of an 'external' object, either from the desktop or // elsewhere on the browser page, onto the canvas. // dropData - The data describing the object being dropped diff --git a/canvas_modules/common-canvas/src/common-canvas/cc-text-toolbar.jsx b/canvas_modules/common-canvas/src/common-canvas/cc-text-toolbar.jsx index 48fb10bf05..c82583f30f 100644 --- a/canvas_modules/common-canvas/src/common-canvas/cc-text-toolbar.jsx +++ b/canvas_modules/common-canvas/src/common-canvas/cc-text-toolbar.jsx @@ -1,5 +1,5 @@ /* - * Copyright 2017-2023 Elyra Authors + * Copyright 2017-2024 Elyra Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -102,8 +102,9 @@ class CommonCanvasTextToolbar extends React.Component { const underlineLabel = this.getLabel("texttoolbar.underline"); const strikethroughLabel = this.getLabel("texttoolbar.strikethroughAction"); + // Set up array for sub-menus. isSelected is set to true for any default option. const subMenuFont = [ - { action: "font-ibm-plex-sans", label: this.getLabel("texttoolbar.fontIBMPlexSans"), enable: true }, + { action: "font-ibm-plex-sans", label: this.getLabel("texttoolbar.fontIBMPlexSans"), enable: true, isSelected: true }, { action: "font-ibm-plex-serif", label: this.getLabel("texttoolbar.fontIBMPlexSerif"), enable: true }, { action: "font-ibm-plex-sans-condensed", label: this.getLabel("texttoolbar.fontIBMPlexSansCon"), enable: true }, { action: "font-ibm-plex-mono", label: this.getLabel("texttoolbar.fontIBMPlexMono"), enable: true }, @@ -118,7 +119,7 @@ class CommonCanvasTextToolbar extends React.Component { const subMenuTextSize = [ { action: "text-size-10", label: "10", enable: true }, { action: "text-size-11", label: "11", enable: true }, - { action: "text-size-12", label: "12", enable: true }, + { action: "text-size-12", label: "12", enable: true, isSelected: true }, { action: "text-size-14", label: "14", enable: true }, { action: "text-size-18", label: "18", enable: true }, { action: "text-size-24", label: "24", enable: true }, @@ -131,22 +132,45 @@ class CommonCanvasTextToolbar extends React.Component { ]; const subMenuAlignHorizontal = [ - { action: "align-left", label: this.getLabel("texttoolbar.alignHorizLeft"), enable: true, iconEnabled: () }, + { action: "align-left", label: this.getLabel("texttoolbar.alignHorizLeft"), enable: true, iconEnabled: (), isSelected: true }, { action: "align-center", label: this.getLabel("texttoolbar.alignHorizCenter"), enable: true, iconEnabled: () }, { action: "align-right", label: this.getLabel("texttoolbar.alignHorizRight"), enable: true, iconEnabled: () } ]; const subMenuAlignVertical = [ - { action: "align-top", label: this.getLabel("texttoolbar.alignVertTop"), enable: true, iconEnabled: () }, + { action: "align-top", label: this.getLabel("texttoolbar.alignVertTop"), enable: true, iconEnabled: (), isSelected: true }, { action: "align-middle", label: this.getLabel("texttoolbar.alignVertMiddle"), enable: true, iconEnabled: () }, { action: "align-bottom", label: this.getLabel("texttoolbar.alignVertBottom"), enable: true, iconEnabled: () } ]; const subMenuOutline = [ { action: "outline-none", label: this.getLabel("texttoolbar.outlineNone"), enable: true }, - { action: "outline-solid", label: this.getLabel("texttoolbar.outlineSolid"), enable: true } + { action: "outline-solid", label: this.getLabel("texttoolbar.outlineSolid"), enable: true, isSelected: true } ]; + // In the arrays above the default option has its isSelected field set to true. We + // now override the isSelected field, if necessary, for all menus, based on whether + // the corresponding format has been set in the formats array. So if, for example, the + // font is set to 'Comic Sans' the element for that font in subMenuFont will have its + // isSelected field set to true and the element for the default font or previously + // selected font will have its isSelected field set to false. + this.setSelectedMenuElement("fontType", this.props.formats, subMenuFont); + this.setSelectedMenuElement("textSize", this.props.formats, subMenuTextSize); + this.setSelectedMenuElement("alignHorizontally", this.props.formats, subMenuAlignHorizontal); + this.setSelectedMenuElement("alignVertically", this.props.formats, subMenuAlignVertical); + this.setSelectedMenuElement("outlineStyle", this.props.formats, subMenuOutline); + + // Get current values (or defaults) for text and background color. + const selectedTextColor = (this.getFormatValue("textColor", this.props.formats) || "#000000"); + const selectedBackgroundColor = (this.getFormatValue("backgroundColor", this.props.formats) || "#FFFFFF"); + + // Get the current values (or defaults) for bold/italics/underline/striketrough attributes + const boldSeletced = (Boolean)(this.getFormatType("bold", this.props.formats)); + const italicsSelected = (Boolean)(this.getFormatType("italics", this.props.formats)); + const textDec = this.getFormatValue("textDecoration", this.props.formats); + const underlineSelected = textDec?.includes("underline"); + const strikethroughSelected = textDec?.includes("strikethrough"); + return { leftBar: [ { action: "submenu-font", @@ -163,10 +187,10 @@ class CommonCanvasTextToolbar extends React.Component { subMenu: subMenuTextSize, closeSubAreaOnClick: true }, - { action: "bold", label: boldLabel, enable: true, iconEnabled: () }, - { action: "italics", label: italicsLabel, enable: true, iconEnabled: () }, - { action: "underline", label: underlineLabel, enable: true, iconEnabled: () }, - { action: "strikethrough", label: strikethroughLabel, enable: true, iconEnabled: () }, + { action: "bold", label: boldLabel, enable: true, iconEnabled: (), isSelected: boldSeletced }, + { action: "italics", label: italicsLabel, enable: true, iconEnabled: (), isSelected: italicsSelected }, + { action: "underline", label: underlineLabel, enable: true, iconEnabled: (), isSelected: underlineSelected }, + { action: "strikethrough", label: strikethroughLabel, enable: true, iconEnabled: (), isSelected: strikethroughSelected }, { divider: true }, { action: "submenu-text-color", label: this.getLabel("texttoolbar.colorText"), @@ -175,6 +199,7 @@ class CommonCanvasTextToolbar extends React.Component { subPanel: ColorPicker, subPanelData: { type: WYSIWYG, + selectedColor: selectedTextColor, clickActionHandler: (color, evt) => this.props.actionHandler("text-color", evt, color) }, closeSubAreaOnClick: true @@ -200,6 +225,7 @@ class CommonCanvasTextToolbar extends React.Component { subPanel: ColorPicker, subPanelData: { type: WYSIWYG, + selectedColor: selectedBackgroundColor, clickActionHandler: (color, evt) => this.props.actionHandler("background-color", evt, color) }, closeSubAreaOnClick: true @@ -215,6 +241,32 @@ class CommonCanvasTextToolbar extends React.Component { }; } + // Sets the isSelected field to true of the element in the menu + // passed in corresponding to the currently specified value for that menu + // in the formats array, + setSelectedMenuElement(type, formats, menu) { + const value = this.getFormatValue(type, formats); + if (value) { + menu.forEach((me) => (me.isSelected = (me.action === value))); + } + } + + // Returns the value for the format type passed in from the array of + // formats passed in. + getFormatValue(type, formats) { + const format = this.getFormatType(type, formats); + return format?.value; + } + + // Returns the format for the type passed in from the array of + // formats passed in. + getFormatType(type, formats) { + if (formats) { + return formats.find((f) => f.type === type); + } + return null; + } + getTextToolbar() { if (this.props.contentType === MARKDOWN) { return this.getMarkdownToolbar(); @@ -233,7 +285,9 @@ class CommonCanvasTextToolbar extends React.Component { if (this.props.isOpen) { textToolbar = ( -
+
({ isOpen: state.texttoolbar.isOpen, pos_x: state.texttoolbar.pos_x, pos_y: state.texttoolbar.pos_y, + formats: state.texttoolbar.formats, contentType: state.texttoolbar.contentType, actionHandler: state.texttoolbar.actionHandler, blurHandler: state.texttoolbar.blurHandler diff --git a/canvas_modules/common-canvas/src/common-canvas/svg-canvas-utils-textarea.js b/canvas_modules/common-canvas/src/common-canvas/svg-canvas-utils-textarea.js index cdd9ec2c2c..70fe924664 100644 --- a/canvas_modules/common-canvas/src/common-canvas/svg-canvas-utils-textarea.js +++ b/canvas_modules/common-canvas/src/common-canvas/svg-canvas-utils-textarea.js @@ -129,6 +129,7 @@ export default class SvgCanvasTextArea { if (d.contentType === WYSIWYG) { this.canvasController.openTextToolbar( pos.x, pos.y, + this.editingTextData.newFormats, WYSIWYG, this.wysiwygActionHandler.bind(this), this.blurInTextToolbar.bind(this) @@ -137,6 +138,7 @@ export default class SvgCanvasTextArea { } else if (this.config.enableMarkdownInComments) { this.canvasController.openTextToolbar( pos.x, pos.y, + null, MARKDOWN, this.markdownActionHandler.bind(this), this.blurInTextToolbar.bind(this) @@ -263,6 +265,7 @@ export default class SvgCanvasTextArea { } else if (action === "bold" || action === "italics") { this.toggleFormat(action); } + this.canvasController.updateTextToolbarFormats(this.editingTextData.newFormats); } // Sets the text color appropriately for the background color passed in. diff --git a/canvas_modules/common-canvas/src/toolbar/toolbar-button-item.jsx b/canvas_modules/common-canvas/src/toolbar/toolbar-button-item.jsx index dc9d584c0e..8b2a658de4 100644 --- a/canvas_modules/common-canvas/src/toolbar/toolbar-button-item.jsx +++ b/canvas_modules/common-canvas/src/toolbar/toolbar-button-item.jsx @@ -28,7 +28,7 @@ import classNames from "classnames"; import { StopFilledAlt, Play, Undo, Redo, Chat, ChatOff, Result, Cut, Copy, Paste, Edit, ColorPalette, Maximize, Minimize, Launch, AddComment, TrashCan, ZoomIn, ZoomOut, - ChevronRight, ChevronDown, ChevronUp, + Checkmark, ChevronRight, ChevronDown, ChevronUp, CenterToFit, OpenPanelFilledLeft } from "@carbon/react/icons"; import { TOOLBAR_STOP, TOOLBAR_RUN, TOOLBAR_UNDO, TOOLBAR_REDO, TOOLBAR_CUT, TOOLBAR_COPY, TOOLBAR_PASTE, TOOLBAR_CLIPBOARD, @@ -210,6 +210,8 @@ class ToolbarButtonItem extends React.Component { const mainClassName = actionObj.purpose ? "content-main dual" : "content-main"; + const checkMark = this.props.actionObj.isSelected && this.props.isInMenu ? (
) : null; + let buttonContent = (
@@ -219,6 +221,7 @@ class ToolbarButtonItem extends React.Component { {textContent}
{chevronDiv} + {checkMark}
); @@ -245,7 +248,7 @@ class ToolbarButtonItem extends React.Component { return button; } - // Returns a civ containing a chevron icon. If the action icon is displaying + // Returns a
containing a chevron icon. If the action icon is displaying // a sub-menu or sub-panel. The chevron will: // * point right if this action item is in a drop down menu. // * point down and be regular size if this action item is displayed with diff --git a/canvas_modules/common-canvas/src/toolbar/toolbar-sub-menu.jsx b/canvas_modules/common-canvas/src/toolbar/toolbar-sub-menu.jsx index 16a9f730fb..60796623cd 100644 --- a/canvas_modules/common-canvas/src/toolbar/toolbar-sub-menu.jsx +++ b/canvas_modules/common-canvas/src/toolbar/toolbar-sub-menu.jsx @@ -47,7 +47,12 @@ class ToolbarSubMenu extends React.Component { } if (this.state.focusAction === "subarea") { - this.setFocusOnFirstItem(); + const selectedItem = this.getFirstCheckedItem(); + if (selectedItem) { + this.setFocusAction(selectedItem.action); + } else { + this.setFocusOnFirstItem(); + } } } @@ -165,6 +170,10 @@ class ToolbarSubMenu extends React.Component { return focuableActions[0]; } + getFirstCheckedItem() { + return this.props.subMenuActions.find((a) => a.isSelected); + } + // Generates an array of JSX objects for a sub-menu defined by the // prop subMenuActions parameter array. generateSubMenuItems() { diff --git a/canvas_modules/common-canvas/src/toolbar/toolbar.scss b/canvas_modules/common-canvas/src/toolbar/toolbar.scss index 657fab4362..10b91e5fb5 100644 --- a/canvas_modules/common-canvas/src/toolbar/toolbar.scss +++ b/canvas_modules/common-canvas/src/toolbar/toolbar.scss @@ -65,6 +65,7 @@ $toolbar-divider-width: 1px; &.is-in-menu { padding-left: 10px; + padding-right: 10px; } & .content-main { @@ -78,6 +79,10 @@ $toolbar-divider-width: 1px; & .toolbar-right-chevron { padding: 4px 0 0; } + + & .checkmark { + padding-top: $spacing-02; + } } .toolbar-popover-list button { @@ -209,6 +214,7 @@ $toolbar-divider-width: 1px; width: inherit; display: flex; justify-content: center; + grid-template-columns: 1fr 16px; &.disabled { pointer-events: none; @@ -251,13 +257,18 @@ $toolbar-divider-width: 1px; } &.is-in-menu { - justify-content: left; + justify-content: space-between; & .content-main { padding: 8px 0 6px; } } + & .checkmark { + pointer-events: none; + padding-top: $spacing-03; + } + &.default { color: $icon-primary; // Used by label and pick up as currentColor in icons. } @@ -309,6 +320,7 @@ $toolbar-divider-width: 1px; padding-left: 8px; word-break: break-word; hyphens: auto; + text-wrap: nowrap; } } @@ -361,7 +373,6 @@ $toolbar-divider-width: 1px; } .toolbar-popover-list { - width: 200px; z-index: 2; // Make sure sub-area appears above bottom panel display: block; position: absolute; // Actual position will be calculated in the code @@ -373,7 +384,7 @@ $toolbar-divider-width: 1px; animation: tovisible 0.25s ease-in-out forwards; // Use keyframe to animate panel visibility &.submenu { - min-width: 100px; + min-width: 150px; } &.subpanel { diff --git a/canvas_modules/harness/src/client/App.js b/canvas_modules/harness/src/client/App.js index 3d5d7dffea..2138c93ad7 100644 --- a/canvas_modules/harness/src/client/App.js +++ b/canvas_modules/harness/src/client/App.js @@ -2147,7 +2147,7 @@ class App extends React.Component { const subMenuTextSize = [ { action: "title", label: "Title", enable: true }, { action: "header", label: "Header", enable: true }, - { action: "subheader", label: "Subheader", enable: true }, + { action: "subheader", label: "Subheader", enable: true, isSelected: true }, { action: "body", label: "Body", enable: true } ]; diff --git a/canvas_modules/harness/src/client/components/custom-canvases/wysiwyg-comments/wysiwyg-comments-flow.json b/canvas_modules/harness/src/client/components/custom-canvases/wysiwyg-comments/wysiwyg-comments-flow.json index ce77c136b4..2d46df58e4 100644 --- a/canvas_modules/harness/src/client/components/custom-canvases/wysiwyg-comments/wysiwyg-comments-flow.json +++ b/canvas_modules/harness/src/client/components/custom-canvases/wysiwyg-comments/wysiwyg-comments-flow.json @@ -15,7 +15,7 @@ "id": "bdf013da-58ec-4592-b971-7f3ecbdb9d77", "x_pos": 70, "y_pos": 60, - "width": 246, + "width": 286, "height": 51, "contentType": "WYSIWYG", "formats": [ @@ -35,7 +35,7 @@ "id": "5538b3ba-1f7e-465d-8290-e778364c113d", "x_pos": 70, "y_pos": 135, - "width": 246, + "width": 286, "height": 51, "contentType": "WYSIWYG", "formats": [ @@ -55,7 +55,7 @@ "id": "7091b5c8-2e51-4180-a84a-7812c583c8e2", "x_pos": 70, "y_pos": 210, - "width": 246, + "width": 290, "height": 51, "contentType": "WYSIWYG", "formats": [ @@ -68,14 +68,14 @@ "value": "text-size-24" } ], - "content": "IBM Plex Condensed", + "content": "IBM Plex Sans Condensed", "associated_id_refs": [] }, { "id": "ac260f24-d5c5-4723-a222-6028b8ed3c11", "x_pos": 70, "y_pos": 285, - "width": 246, + "width": 287, "height": 51, "contentType": "WYSIWYG", "formats": [ @@ -95,7 +95,7 @@ "id": "cd3d2ca8-00ee-4622-9fee-ecd09a5d2477", "x_pos": 70, "y_pos": 360, - "width": 246, + "width": 285, "height": 51, "contentType": "WYSIWYG", "formats": [ @@ -461,11 +461,11 @@ "formats": [ { "type": "backgroundColor", - "value": "#B7EEBF" + "value": "#A7F0BA" }, { "type": "textColor", - "value": "#E75B5C" + "value": "#FC7B1D" }, { "type": "fontType", diff --git a/docs/pages/03.02.02-toolbar-config.md b/docs/pages/03.02.02-toolbar-config.md index 04a25b7bd9..42c3f46cb8 100644 --- a/docs/pages/03.02.02-toolbar-config.md +++ b/docs/pages/03.02.02-toolbar-config.md @@ -124,12 +124,19 @@ Here is an example of an action object which must contain a unique `action` fiel * **tooltip** - A string or JSX object. The tooltip that will be displayed for the action. If this is not provided the label will be displayed as the tooltip instead. -* **isSelected** - A boolean. When set to true the toolbar button displays a selection highlight (which is a blue bar along the bottom border of the toolbar item). This is useful for implementing a button that switches on and off a mode, as opposed to a regular button which does not have any state. +* **isSelected** - A boolean. When set to true the toolbar button displays a selection highlight. This is displayed as either a blue bar along the bottom border of buttons in the toolbar - This property can also be used to indicate a current state between a number of mutually exclusive settings. In this case, one button would be added to the toolbar for each setting and then the `isSelected` property would be set to true for the setting that is currently active. Then, when the user clicks a different option in the set, the code would set `isSelected` to true for that button and set it to false for the previously selected button. (This would give behavior like a radio button set.) + or a checkmark for items that appear in sub-menus. + + + + When applied This is useful for implementing a button that switches on and off a mode, as opposed to a regular button which does not have any state. + + + This property can also be used to indicate a current state between a number of mutually exclusive settings. In this case, one button would be added to the toolbar for each setting and then the `isSelected` property would be set to true for the setting that is currently active. Then, when the user clicks a different option in the set, the application code would set `isSelected` to true for that button and set it to false for the previously selected button. (This would give behavior like a radio button set.) * **className** - This a string that will be appended to the `class` field for the top-level `
` that surrounds the action button. This can be used to set application-specific CSS for the button. diff --git a/docs/pages/assets/cc-toolbar-action-selected-menu.png b/docs/pages/assets/cc-toolbar-action-selected-menu.png new file mode 100644 index 0000000000..84545d926e Binary files /dev/null and b/docs/pages/assets/cc-toolbar-action-selected-menu.png differ