diff --git a/Composer/packages/adaptive-flow/src/adaptive-flow-editor/utils/cursorTracker/tabMove.ts b/Composer/packages/adaptive-flow/src/adaptive-flow-editor/utils/cursorTracker/tabMove.ts index b7dfcba882..a76c503699 100644 --- a/Composer/packages/adaptive-flow/src/adaptive-flow-editor/utils/cursorTracker/tabMove.ts +++ b/Composer/packages/adaptive-flow/src/adaptive-flow-editor/utils/cursorTracker/tabMove.ts @@ -35,6 +35,18 @@ export function handleTabMove(currentElement: SelectorElement, selectableElement let nextElement: SelectorElement; const selectableChildren = findSelectableChildren(currentElement, selectableElements); const selectableParent = findSelectableParent(currentElement, selectableElements); + const selectableSiblings = selectableElements.filter( + (el) => + !selectableChildren.includes(el) && + el.bounds.top > currentElement.bounds.top - 10 && + el.bounds.top < currentElement.bounds.top + 10 + ); + const nextSibling = locateNearestElement( + currentElement, + selectableSiblings, + command === KeyboardCommandTypes.Cursor.MoveNext ? Direction.Right : Direction.Left, + ['isNode', 'isEdgeMenu'] + ); const findElementWithSuffix = (suffix) => { return selectableElements.find((element) => element.selectedId === `${selectableParent?.selectedId}${suffix}`); }; @@ -42,12 +54,15 @@ export function handleTabMove(currentElement: SelectorElement, selectableElement if (selectableChildren.length > 0) { // Tab to inner selectable element. nextElement = selectableChildren[0]; + } else if (nextSibling && nextSibling !== currentElement) { + // Tab nearest sibling element. + nextElement = nextSibling; } else { const hasInlineLinkElement = currentElement.selectedId.endsWith('dot') && findElementWithSuffix('link'); if (hasInlineLinkElement) { nextElement = findElementWithSuffix('link') || currentElement; } else { - // Perform like presssing down arrow key. + // Perform like pressing down arrow key. nextElement = locateNearestElement(currentElement, selectableElements, Direction.Down, [ 'isNode', 'isEdgeMenu', @@ -55,7 +70,9 @@ export function handleTabMove(currentElement: SelectorElement, selectableElement } } } else if (command === KeyboardCommandTypes.Cursor.MovePrevious) { - if (selectableParent) { + if (nextSibling && nextSibling !== currentElement) { + nextElement = nextSibling; + } else if (selectableParent) { // Tab to parent. if (currentElement.isInlineLinkElement) { nextElement = findElementWithSuffix('dot') || selectableParent; diff --git a/Composer/packages/adaptive-form/src/components/CollapseField.tsx b/Composer/packages/adaptive-form/src/components/CollapseField.tsx index c7427c5807..08e8bbab75 100644 --- a/Composer/packages/adaptive-form/src/components/CollapseField.tsx +++ b/Composer/packages/adaptive-form/src/components/CollapseField.tsx @@ -29,6 +29,7 @@ const styles = { display: flex; margin: 4px -18px; align-items: center; + width: 100%; `, }; diff --git a/Composer/packages/client/src/pages/design/SideBar.tsx b/Composer/packages/client/src/pages/design/SideBar.tsx index 0c6c4f21c7..bf6c799c21 100644 --- a/Composer/packages/client/src/pages/design/SideBar.tsx +++ b/Composer/packages/client/src/pages/design/SideBar.tsx @@ -89,6 +89,7 @@ const SideBar: React.FC = React.memo(({ projectId }) => { removeSkillFromBotProject, updateZoomRate, deleteTrigger, + setMessage: announce, } = useRecoilValue(dispatcherState); const skillUsedInBotsMap = useRecoilValue(skillUsedInBotsSelector); @@ -181,12 +182,12 @@ const SideBar: React.FC = React.memo(({ projectId }) => { } async function handleDeleteTrigger(projectId: string, dialogId: string, index: number) { - const content = DialogdeleteTrigger( - projectDialogsMap[projectId], - dialogId, - index, - async (trigger) => await deleteTrigger(projectId, dialogId, trigger) - ); + const content = DialogdeleteTrigger(projectDialogsMap[projectId], dialogId, index, async (trigger) => { + await deleteTrigger(projectId, dialogId, trigger); + announce( + formatMessage(`The trigger {triggerName} has been deleted`, { triggerName: trigger.$designer?.name ?? '' }) + ); + }); if (content) { await updateDialog({ id: dialogId, content, projectId }); diff --git a/Composer/packages/lib/code-editor/src/components/toolbar/__tests__/ToolbarButtonMenu.test.tsx b/Composer/packages/lib/code-editor/src/components/toolbar/__tests__/ToolbarButtonMenu.test.tsx index cf0c1b0990..33be12fa34 100644 --- a/Composer/packages/lib/code-editor/src/components/toolbar/__tests__/ToolbarButtonMenu.test.tsx +++ b/Composer/packages/lib/code-editor/src/components/toolbar/__tests__/ToolbarButtonMenu.test.tsx @@ -117,7 +117,7 @@ describe('', () => { jest.runAllTimers(); }); - expect((await screen.findAllByText(/this/)).length).toBe(2); + expect((await screen.findAllByText(/this/)).length).toBe(3); }); it('property: Should expand property in the menu on click if not leaf', async () => { diff --git a/Composer/packages/lib/code-editor/src/hooks/useSearchableMenuListCallback.tsx b/Composer/packages/lib/code-editor/src/hooks/useSearchableMenuListCallback.tsx index 767ff6f853..daa23c7a5e 100644 --- a/Composer/packages/lib/code-editor/src/hooks/useSearchableMenuListCallback.tsx +++ b/Composer/packages/lib/code-editor/src/hooks/useSearchableMenuListCallback.tsx @@ -8,6 +8,7 @@ import { SearchBox } from '@fluentui/react/lib/SearchBox'; import { Stack } from '@fluentui/react/lib/Stack'; import { IRenderFunction } from '@fluentui/react/lib/Utilities'; import * as React from 'react'; +import { Announced } from '@fluentui/react/lib/Announced'; import { useDebouncedSearchCallbacks } from './useDebouncedSearchCallbacks'; @@ -30,8 +31,20 @@ export const useSearchableMenuListCallback = ( setQuery(''); }, [setQuery]); + const searchComplete = !!query; + const callback = React.useCallback( (menuListProps?: IContextualMenuListProps, defaultRender?: IRenderFunction) => { + const searchCompleteAnnouncement = searchComplete + ? formatMessage( + `Search for the {query}. Found {count, plural, + =1 {one result} + other {# results} + }`, + { query, count: menuListProps?.items?.filter((item) => item?.key && item.key !== 'no_results').length } + ) + : undefined; + return ( {headerRenderer?.()} @@ -42,11 +55,12 @@ export const useSearchableMenuListCallback = ( onAbort={onSearchAbort} onChange={onSearchQueryChange} /> + {defaultRender?.(menuListProps)} ); }, - [searchFiledPlaceHolder, headerRenderer, onReset, onSearchQueryChange] + [searchFiledPlaceHolder, headerRenderer, onReset, onSearchQueryChange, searchComplete] ); return { onRenderMenuList: callback, query, onReset }; diff --git a/Composer/packages/lib/code-editor/src/lu/__tests__/InsertEntityButton.test.tsx b/Composer/packages/lib/code-editor/src/lu/__tests__/InsertEntityButton.test.tsx index 51fc8645fa..afc6a6307b 100644 --- a/Composer/packages/lib/code-editor/src/lu/__tests__/InsertEntityButton.test.tsx +++ b/Composer/packages/lib/code-editor/src/lu/__tests__/InsertEntityButton.test.tsx @@ -86,6 +86,6 @@ describe('', () => { jest.runAllTimers(); }); - expect((await screen.findAllByText(/.*target.*/)).length).toBe(1); + expect((await screen.findAllByText(/.*target.*/)).length).toBe(2); }); }); diff --git a/extensions/azurePublish/yarn-berry.lock b/extensions/azurePublish/yarn-berry.lock index 93af441aa9..fd32472569 100644 --- a/extensions/azurePublish/yarn-berry.lock +++ b/extensions/azurePublish/yarn-berry.lock @@ -1879,7 +1879,7 @@ __metadata: "@bfc/code-editor@file:../../Composer/packages/lib/code-editor::locator=azurePublish%40workspace%3A.": version: 0.0.0 - resolution: "@bfc/code-editor@file:../../Composer/packages/lib/code-editor#../../Composer/packages/lib/code-editor::hash=2fd137&locator=azurePublish%40workspace%3A." + resolution: "@bfc/code-editor@file:../../Composer/packages/lib/code-editor#../../Composer/packages/lib/code-editor::hash=cf4a8a&locator=azurePublish%40workspace%3A." dependencies: "@emotion/react": ^11.1.3 "@emotion/styled": ^11.1.3 @@ -1902,7 +1902,7 @@ __metadata: "@bfc/ui-shared": "*" react: 16.13.1 react-dom: 16.13.1 - checksum: 12992120cb3addfebd48ede1740792029a4c6ce268ab0be95c110bd60cbbe9993830d60753dbc7d5c87e992f64fdc122af09ebfe6e9fcbfc747102560e1fb574 + checksum: f3773eb308e7e1d6db3d13220510b48c7659febca2441213fbc3deeff35abddf559f8cababdea58a5630ae214124f82299ce1d86fe89a5196369adc9ab9234f7 languageName: node linkType: hard