]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-18918 Fixing accessibility issues in global search
authorRevanshu Paliwal <revanshu.paliwal@sonarsource.com>
Thu, 30 Mar 2023 09:46:55 +0000 (11:46 +0200)
committersonartech <sonartech@sonarsource.com>
Thu, 30 Mar 2023 20:03:07 +0000 (20:03 +0000)
server/sonar-web/src/main/js/app/components/global-search/GlobalSearch.tsx
server/sonar-web/src/main/js/app/components/nav/component/branch-like/BranchLikeNavigation.tsx

index 605b251614f43afc93bb4b439c8d2a7ae302fb06..131c63ce23cba6ac168f10013743cca154067e2c 100644 (file)
@@ -31,6 +31,7 @@ import {
 import { debounce, uniqBy } from 'lodash';
 import * as React from 'react';
 import { getSuggestions } from '../../../api/components';
+import FocusOutHandler from '../../../components/controls/FocusOutHandler';
 import OutsideClickHandler from '../../../components/controls/OutsideClickHandler';
 import Tooltip from '../../../components/controls/Tooltip';
 import { Router, withRouter } from '../../../components/hoc/withRouter';
@@ -39,6 +40,7 @@ import { isInput, isShortcut } from '../../../helpers/keyboardEventHelpers';
 import { KeyboardKeys } from '../../../helpers/keycodes';
 import { translate, translateWithParameters } from '../../../helpers/l10n';
 import { getKeyboardShortcutEnabled } from '../../../helpers/preferences';
+import { scrollToElement } from '../../../helpers/scrolling';
 import { getComponentOverviewUrl } from '../../../helpers/urls';
 import { ComponentQualifier } from '../../../types/component';
 import { Dict } from '../../../types/types';
@@ -277,7 +279,12 @@ export class GlobalSearch extends React.PureComponent<Props, State> {
       const node = this.nodes[this.state.selected];
 
       if (node && this.node) {
-        node.scrollIntoView();
+        // using scrollIntoView here is creating some weird scroll behaviour when scrolling
+        scrollToElement(node, {
+          topOffset: 30,
+          bottomOffset: 30,
+          parent: this.node,
+        });
       }
     }
   };
@@ -357,25 +364,10 @@ export class GlobalSearch extends React.PureComponent<Props, State> {
   render() {
     const { open, query, results, more, loadingMore, selected, loading } = this.state;
 
-    if (!open && !query) {
-      return (
-        <Tooltip mouseEnterDelay={INTERACTIVE_TOOLTIP_DELAY} overlay={translate('search_verb')}>
-          <InteractiveIcon
-            className="it__search-icon"
-            Icon={MenuSearchIcon}
-            aria-label={translate('search_verb')}
-            currentColor={true}
-            onClick={this.handleFocus}
-            size="medium"
-          />
-        </Tooltip>
-      );
-    }
-
     const list = this.getPlainComponentsList(results, more);
 
     const search = (
-      <div role="search" className="sw-min-w-abs-200 sw-max-w-abs-350 sw-w-full">
+      <div className="sw-min-w-abs-200 sw-max-w-abs-350 sw-w-full">
         <Popup
           allowResizing={true}
           overlay={
@@ -385,6 +377,7 @@ export class GlobalSearch extends React.PureComponent<Props, State> {
                 maxHeight="38rem"
                 innerRef={(node: HTMLUListElement | null) => (this.node = node)}
                 size="auto"
+                aria-owns="global-search-input"
               >
                 <GlobalSearchResults
                   query={query}
@@ -409,6 +402,7 @@ export class GlobalSearch extends React.PureComponent<Props, State> {
           zLevel={PopupZLevel.Global}
         >
           <InputSearch
+            id="global-search-input"
             className="sw-w-full"
             autoFocus={open}
             innerRef={this.searchInputRef}
@@ -428,10 +422,27 @@ export class GlobalSearch extends React.PureComponent<Props, State> {
       </div>
     );
 
-    return open ? (
-      <OutsideClickHandler onClickOutside={this.handleClickOutside}>{search}</OutsideClickHandler>
-    ) : (
-      search
+    return (
+      <form role="search">
+        {!open && !query ? (
+          <Tooltip mouseEnterDelay={INTERACTIVE_TOOLTIP_DELAY} overlay={translate('search_verb')}>
+            <InteractiveIcon
+              className="it__search-icon"
+              Icon={MenuSearchIcon}
+              aria-label={translate('search_verb')}
+              currentColor={true}
+              onClick={this.handleFocus}
+              size="medium"
+            />
+          </Tooltip>
+        ) : (
+          <FocusOutHandler onFocusOut={this.handleClickOutside}>
+            <OutsideClickHandler onClickOutside={this.handleClickOutside}>
+              {search}
+            </OutsideClickHandler>
+          </FocusOutHandler>
+        )}
+      </form>
     );
   }
 }
index b8296bd435545772933be8ac77271675a6509199..db755f32bd447aee9fe067205e3405563abae6ad 100644 (file)
@@ -20,6 +20,7 @@
 import { ButtonSecondary, Popup, PopupPlacement, PopupZLevel } from 'design-system';
 import * as React from 'react';
 import EscKeydownHandler from '../../../../../components/controls/EscKeydownHandler';
+import FocusOutHandler from '../../../../../components/controls/FocusOutHandler';
 import OutsideClickHandler from '../../../../../components/controls/OutsideClickHandler';
 import { AlmKeys, ProjectAlmBindingResponse } from '../../../../../types/alm-settings';
 import { BranchLike } from '../../../../../types/branch-like';
@@ -63,50 +64,48 @@ export function BranchLikeNavigation(props: BranchLikeNavigationProps) {
     <CurrentBranchLike component={component} currentBranchLike={currentBranchLike} />
   );
 
+  const handleOutsideClick = () => {
+    setIsMenuOpen(false);
+  };
+
   return (
     <div className="sw-flex sw-items-center sw-ml-2 it__branch-like-navigation-toggler-container">
-      <EscKeydownHandler
-        onKeydown={() => {
-          setIsMenuOpen(false);
-        }}
+      <Popup
+        allowResizing={true}
+        overlay={
+          isMenuOpen && (
+            <FocusOutHandler onFocusOut={handleOutsideClick}>
+              <EscKeydownHandler onKeydown={handleOutsideClick}>
+                <OutsideClickHandler onClickOutside={handleOutsideClick}>
+                  <Menu
+                    branchLikes={branchLikes}
+                    canAdminComponent={canAdminComponent}
+                    component={component}
+                    currentBranchLike={currentBranchLike}
+                    onClose={() => {
+                      setIsMenuOpen(false);
+                    }}
+                  />
+                </OutsideClickHandler>
+              </EscKeydownHandler>
+            </FocusOutHandler>
+          )
+        }
+        placement={PopupPlacement.BottomLeft}
+        zLevel={PopupZLevel.Global}
       >
-        <OutsideClickHandler
-          onClickOutside={() => {
-            setIsMenuOpen(false);
+        <ButtonSecondary
+          className="sw-max-w-abs-350"
+          onClick={() => {
+            setIsMenuOpen(!isMenuOpen);
           }}
+          disabled={!isMenuEnabled}
+          aria-expanded={isMenuOpen}
+          aria-haspopup="menu"
         >
-          <Popup
-            allowResizing={true}
-            overlay={
-              isMenuOpen && (
-                <Menu
-                  branchLikes={branchLikes}
-                  canAdminComponent={canAdminComponent}
-                  component={component}
-                  currentBranchLike={currentBranchLike}
-                  onClose={() => {
-                    setIsMenuOpen(false);
-                  }}
-                />
-              )
-            }
-            placement={PopupPlacement.BottomLeft}
-            zLevel={PopupZLevel.Global}
-          >
-            <ButtonSecondary
-              className="sw-max-w-abs-350"
-              onClick={() => {
-                setIsMenuOpen(!isMenuOpen);
-              }}
-              disabled={!isMenuEnabled}
-              aria-expanded={isMenuOpen}
-              aria-haspopup="menu"
-            >
-              {currentBranchLikeElement}
-            </ButtonSecondary>
-          </Popup>
-        </OutsideClickHandler>
-      </EscKeydownHandler>
+          {currentBranchLikeElement}
+        </ButtonSecondary>
+      </Popup>
 
       <div className="sw-ml-2">
         <BranchHelpTooltip