diff --git a/Composer/packages/client/src/components/ProjectTree/ProjectTree.tsx b/Composer/packages/client/src/components/ProjectTree/ProjectTree.tsx index 24a89a54d5..1ce1f81057 100644 --- a/Composer/packages/client/src/components/ProjectTree/ProjectTree.tsx +++ b/Composer/packages/client/src/components/ProjectTree/ProjectTree.tsx @@ -185,6 +185,7 @@ export const ProjectTree: React.FC = ({ setPageElementState('design', { ...pageElements, [name]: value }); const [filter, setFilter] = useState(''); + const [isMenuOpen, setMenuOpen] = useState(false); const formDialogComposerFeatureEnabled = useFeatureFlag('FORM_DIALOG'); const [selectedLink, setSelectedLink] = useState | undefined>(defaultSelected); const delayedSetFilter = throttle((newValue) => setFilter(newValue), 200); @@ -328,8 +329,10 @@ export const ProjectTree: React.FC = ({ hasChildren={!bot.isRemote} icon={bot.isRemote ? icons.EXTERNAL_SKILL : icons.BOT} isActive={doesLinkMatch(link, selectedLink)} + isMenuOpen={isMenuOpen} link={link} menu={menu} + menuOpenCallback={setMenuOpen} textWidth={leftSplitWidth - TREE_PADDING} onSelect={handleOnSelect} /> @@ -398,8 +401,10 @@ export const ProjectTree: React.FC = ({ showProps icon={isFormDialog ? icons.FORM_DIALOG : icons.DIALOG} isActive={doesLinkMatch(dialogLink, selectedLink)} + isMenuOpen={isMenuOpen} link={dialogLink} menu={menu} + menuOpenCallback={setMenuOpen} textWidth={leftSplitWidth - TREE_PADDING} onSelect={handleOnSelect} /> @@ -434,6 +439,7 @@ export const ProjectTree: React.FC = ({ extraSpace={INDENT_PER_LEVEL} icon={icons.TRIGGER} isActive={doesLinkMatch(link, selectedLink)} + isMenuOpen={isMenuOpen} link={link} menu={[ { @@ -444,6 +450,7 @@ export const ProjectTree: React.FC = ({ }, }, ]} + menuOpenCallback={setMenuOpen} textWidth={leftSplitWidth - TREE_PADDING} onSelect={handleOnSelect} /> @@ -502,7 +509,14 @@ export const ProjectTree: React.FC = ({ `} role="grid" > - + ); }; @@ -651,7 +665,9 @@ export const ProjectTree: React.FC = ({ {onAllSelected != null ? ( diff --git a/Composer/packages/client/src/components/ProjectTree/treeItem.tsx b/Composer/packages/client/src/components/ProjectTree/treeItem.tsx index 585570fff4..92d497989d 100644 --- a/Composer/packages/client/src/components/ProjectTree/treeItem.tsx +++ b/Composer/packages/client/src/components/ProjectTree/treeItem.tsx @@ -3,7 +3,7 @@ /** @jsx jsx */ import { jsx, css } from '@emotion/core'; -import React from 'react'; +import React, { useState } from 'react'; import { FontWeights } from '@uifabric/styling'; import { FontSizes } from '@uifabric/fluent-theme'; import { OverflowSet, IOverflowSetItemProps } from 'office-ui-fabric-react/lib/OverflowSet'; @@ -79,14 +79,14 @@ export const moreButton = (isActive: boolean): IButtonStyles => { }; }; -const navItem = (isActive: boolean, isBroken: boolean) => css` +const navItem = (isActive: boolean, isBroken: boolean, isAnyMenuOpen: boolean, menuOpenHere: boolean) => css` label: navItem; min-width: 100%; position: relative; height: 24px; font-size: 12px; - color: ${isActive ? NeutralColors.white : '#545454'}; - background: ${isActive ? '#0078d4' : 'transparent'}; + color: ${isActive && !menuOpenHere ? NeutralColors.white : '#545454'}; + background: ${isActive ? '#0078d4' : menuOpenHere ? '#f2f2f2' : 'transparent'}; opacity: ${isBroken ? 0.5 : 1}; font-weight: ${isActive ? FontWeights.semibold : FontWeights.regular}; @@ -94,14 +94,16 @@ const navItem = (isActive: boolean, isBroken: boolean) => css` flex-direction: row; align-items: center; - &:hover { + ${isAnyMenuOpen + ? '' + : `&:hover { color: #545454; background: #f2f2f2; .dialog-more-btn { visibility: visible; } - } + }`} &:focus { outline: none; @@ -205,6 +207,8 @@ interface ITreeItemProps { textWidth?: number; extraSpace?: number; hasChildren?: boolean; + menuOpenCallback?: (boolean) => void; + isMenuOpen?: boolean; } const renderTreeMenuItem = (link: TreeLink) => (item: TreeMenuItem) => { @@ -229,7 +233,7 @@ const renderTreeMenuItem = (link: TreeLink) => (item: TreeMenuItem) => { }; }; -const onRenderItem = (textWidth: number) => (item: IOverflowSetItemProps) => { +const onRenderItem = (textWidth: number, isMenuOpen: boolean) => (item: IOverflowSetItemProps) => { const { diagnostics = [] } = item; const warnings: Diagnostic[] = diagnostics.filter((diag) => diag.severity === DiagnosticSeverity.Warning); const errors: Diagnostic[] = diagnostics.filter((diag) => diag.severity === DiagnosticSeverity.Error); @@ -310,7 +314,11 @@ const onRenderItem = (textWidth: number) => (item: IOverflowSetItemProps) => { ); }; -const onRenderOverflowButton = (isActive: boolean) => { +const onRenderOverflowButton = ( + isActive: boolean, + menuOpenCallback: (boolean) => void, + setThisItemSelected: (boolean) => void +) => { const moreLabel = formatMessage('Actions'); return (overflowItems: IContextualMenuItem[] | undefined) => { if (overflowItems == null) return null; @@ -322,7 +330,18 @@ const onRenderOverflowButton = (isActive: boolean) => { data-is-focusable={isActive} data-testid="dialogMoreButton" menuIconProps={{ iconName: 'MoreVertical' }} - menuProps={{ items: overflowItems, styles: menuStyle }} + menuProps={{ + items: overflowItems, + styles: menuStyle, + onMenuOpened: () => { + setThisItemSelected(true); + menuOpenCallback(true); + }, + onMenuDismissed: () => { + setThisItemSelected(false); + menuOpenCallback(false); + }, + }} role="cell" styles={moreButton(isActive)} onKeyDown={(e) => { @@ -346,7 +365,11 @@ export const TreeItem: React.FC = ({ hasChildren = false, menu = [], extraSpace = 0, + menuOpenCallback = () => {}, + isMenuOpen = false, }) => { + const [thisItemSelected, setThisItemSelected] = useState(false); + const a11yLabel = `${dialogName ?? '$Root'}_${link.displayName}`; const overflowMenu = menu.map(renderTreeMenuItem(link)); @@ -358,7 +381,7 @@ export const TreeItem: React.FC = ({ return (
= ({ overflowItems={overflowMenu} role="row" styles={{ item: { flex: 1 } }} - onRenderItem={onRenderItem(textWidth - spacerWidth + extraSpace)} - onRenderOverflowButton={onRenderOverflowButton(!!isActive)} + onRenderItem={onRenderItem(textWidth - spacerWidth + extraSpace, isMenuOpen)} + onRenderOverflowButton={onRenderOverflowButton(!!isActive, menuOpenCallback, setThisItemSelected)} />
);