Repository: Sage/carbon (ts)

Issue:
Multi Action Button - Accessibility(Speech Recognition) reinforcement request  
### Desired behaviour

 For the users who are not able to click using a mouse or a keyboard, **Multi Action Button** should show hidden buttons with onClick event not only with onMouseLeave or Tab key event.

### Current behaviour

**Multi Action Button** currently shows hidden buttons only with mouseover or keyboard events. The users with hand disability should go through one more step, saying 'press enter key' and this is not intuitive. (Video attached) 

https://user-images.githubusercontent.com/90848080/202129174-6bbe9a42-494e-4d17-9896-b347c8f82a4a.mov



### Suggested Solution

 Controlling the state of the hidden buttons under **Multi Action Button** with onClick event along with the current mouseover and keyboard will reinforce the accessibility. 

### CodeSandbox or Storybook URL

https://codesandbox.io/s/speech-recognition-issue-8g7v3z?file=/src/index.js

### Anything else we should know?

_No response_

### Confidentiality

- [X] I confirm there is no confidential or commercially sensitive information included.

Pull request:
fix(multi-action-button, split-button): open menu on click
The additional buttons are now shown on click of the toggle button, rather than just on hover. This means that Voice Control users can activate the button by just saying its name (or the appropriate number if going through "show numbers"). Also tidy up by removing aria-haspopup on the surrouding div, this was already on the toggle button itself and from ARIA 1.2 is no longer valid on generic elements like a div.

fix #5615

### Proposed behaviour

<!--
A clear and concise description of what changes this PR makes.

If applicable, add screenshots of a codesandbox to help explain your request. You can paste these directly into GitHub.

Please DO NOT share screenshots or the source code of your project.

You can create a codesandbox to show the behaviour before/after this pull request by forking this template https://codesandbox.io/s/carbon-quickstart-j5pb2

If you include a CodeSandbox link, the bot will fork it with the new built version of carbon.
If you have a commit that includes fixes #XXXX and issue #XXXX has a CodeSandbox link in the body, the bot will fork
it with the new built version of carbon.
-->

There should be a click action on the main button of MultiActionButton, and the toggle button of SplitButton, that opens the child buttons. This enables Voice Control users to open the additional buttons without further instructions needed (see video on the original issue).

The div wrapper of both components should not have aria-haspopup=true, as it is only the (toggle) button that opens the "menu" of additional buttons, and although it's legal as of ARIA 1.1 to have this attribute on any element (and therefore flags no issue in Axe), this is going away in ARIA 1.2 - see https://www.w3.org/TR/wai-aria-1.2/#aria-haspopup and the third "NOTE" green box: "This property is being deprecated as a global property in ARIA 1.2. In future versions it will only be allowed on roles where it is specifically supported." (`button` is listed as one of the allowed roles).

### Current behaviour

<!--
A clear and concise description of the behaviour before this change.

If applicable, add screenshots. You can paste these directly into GitHub.
-->

The additional buttons open on mouseenter, but not on click.

The `aria-haspopup` property is applied to the wrapping div as well as to the button that actually opens the popup.

### Checklist

<!-- Each PR should include the following -->

- [X] Commits follow our style guide
- [X] Related issues linked in commit messages if required
- [X] Screenshots are included in the PR if useful
- [X] All themes are supported if required
- [X] Unit tests added or updated if required
- [X] Cypress automation tests added or updated if required
- [X] Storybook added or updated if required
- [X] Translations added or updated (including creating or amending translation keys table in storybook) if required
- [X] Typescript `d.ts` file added or updated if required
- [X] Related docs have been updated if required

#### QA

- [ ] Tested in CodeSandbox/storybook
- [ ] Add new Cypress test coverage if required
- [ ] Carbon implementation matches Design System/designs
- [ ] UI Tests GitHub check reviewed if required

### Additional context

<!-- Add any other context or links about the pull request here. -->

### Testing instructions

<!-- How can a reviewer test this PR? -->
Test that the issue with Voice Control shown in the video attached to the linked issue has been fixed. Test with SpitButton as well as MultiActionButton (as both had the same problem).

Ensure that accessibility has not been impacted - that there are no new Axe errors on either component and there are no issues using them with Voiceover on Safari or NVDA with supported browsers on Windows, that were not present before.


<!-- Add CodeSandbox here -->


Patch:
diff --git a/src/components/multi-action-button/__snapshots__/multi-action-button.spec.tsx.snap b/src/components/multi-action-button/__snapshots__/multi-action-button.spec.tsx.snap
index 84965b8a8..1da9ef968 100644
--- a/src/components/multi-action-button/__snapshots__/multi-action-button.spec.tsx.snap
+++ b/src/components/multi-action-button/__snapshots__/multi-action-button.spec.tsx.snap
@@ -358,10 +358,8 @@ exports[`MultiActionButton when rendered should match the snapshot 1`] = `
 }
 
 <div
-  aria-haspopup="true"
   className="c0"
   data-component="multi-action-button"
-  onClick={[Function]}
   onMouseLeave={[Function]}
 >
   <button
@@ -373,6 +371,7 @@ exports[`MultiActionButton when rendered should match the snapshot 1`] = `
     data-element="toggle-button"
     disabled={false}
     draggable={false}
+    onClick={[Function]}
     onKeyDown={[Function]}
     onMouseEnter={[Function]}
     onTouchStart={[Function]}
diff --git a/src/components/multi-action-button/multi-action-button.component.tsx b/src/components/multi-action-button/multi-action-button.component.tsx
index c2a656c33..1fdf46423 100644
--- a/src/components/multi-action-button/multi-action-button.component.tsx
+++ b/src/components/multi-action-button/multi-action-button.component.tsx
@@ -34,6 +34,7 @@ export const MultiActionButton = ({
   text,
   subtext,
   width,
+  onClick,
   "data-element": dataElement,
   "data-role": dataRole,
   ...rest
@@ -115,11 +116,24 @@ export const MultiActionButton = ({
     }
   };
 
+  const handleInsideClick = useClickAwayListener(hideButtons);
+
+  const handleClick = (
+    ev: React.MouseEvent<HTMLButtonElement | HTMLAnchorElement>
+  ) => {
+    showButtons();
+    handleInsideClick();
+    if (onClick) {
+      onClick(ev as React.MouseEvent<HTMLButtonElement>);
+    }
+  };
+
   const mainButtonProps = {
     disabled,
     displayed: showAdditionalButtons,
     onTouchStart: showButtons,
     onKeyDown: handleMainButtonKeyDown,
+    onClick: handleClick,
     buttonType,
     size,
     subtext,
@@ -143,8 +157,6 @@ export const MultiActionButton = ({
     </Popover>
   );
 
-  const handleClick = useClickAwayListener(hideButtons);
-
   const hideButtonsIfTriggerNotFocused = useCallback(() => {
     if (buttonRef.current === document.activeElement) return;
     setShowAdditionalButtons(false);
@@ -154,9 +166,7 @@ export const MultiActionButton = ({
 
   return (
     <StyledMultiActionButton
-      aria-haspopup="true"
       onMouseLeave={hideButtonsIfTriggerNotFocused}
-      onClick={handleClick}
       ref={ref}
       data-component="multi-action-button"
       data-element={dataElement}
diff --git a/src/components/multi-action-button/multi-action-button.spec.tsx b/src/components/multi-action-button/multi-action-button.spec.tsx
index f17da5054..7511b32bb 100644
--- a/src/components/multi-action-button/multi-action-button.spec.tsx
+++ b/src/components/multi-action-button/multi-action-button.spec.tsx
@@ -61,13 +61,15 @@ describe("MultiActionButton", () => {
     const additionalButtonsSelector = '[data-element="additional-buttons"]';
     let container: HTMLDivElement | null;
     let mainButton: ReactWrapper;
+    const onClick = jest.fn();
 
     beforeEach(() => {
+      onClick.mockClear();
       container = document.createElement("div");
       container.id = "enzymeContainer";
       document.body.appendChild(container);
       wrapper = mount(
-        <MultiActionButton text="Main Button">
+        <MultiActionButton text="Main Button" onClick={onClick}>
           <Button>First</Button>
           <Button>Second</Button>
         </MultiActionButton>,
@@ -86,6 +88,20 @@ describe("MultiActionButton", () => {
       container = null;
     });
 
+    describe("when the main button is clicked", () => {
+      it("the additional buttons are shown", () => {
+        mainButton.simulate("click");
+
+        expect(wrapper.find(Button).at(0).getDOMNode()).toBeVisible();
+      });
+
+      it("the passed onClick handler is called", () => {
+        mainButton.simulate("click");
+
+        expect(onClick).toHaveBeenCalledTimes(1);
+      });
+    });
+
     describe("using keyboard to open children container", () => {
       it.each([
         ["Enter", "Enter"],
@@ -506,7 +522,7 @@ describe("MultiActionButton", () => {
         wrapper.unmount();
       });
 
-      it("the handler should be called on the main button", () => {
+      it("the handler should be called on the clicked button", () => {
         mainButton.simulate("mouseenter");
         const button = wrapper
           .find('[data-element="additional-buttons"]')
@@ -580,7 +596,7 @@ describe("MultiActionButton", () => {
           );
 
           wrapper
-            .find(StyledMultiActionButton)
+            .find('button[data-element="toggle-button"]')
             .getDOMNode()
             .dispatchEvent(nativeInputEvent);
 
diff --git a/src/components/split-button/split-button.component.tsx b/src/components/split-button/split-button.component.tsx
index 4bd0895e8..e6a3f5d66 100644
--- a/src/components/split-button/split-button.component.tsx
+++ b/src/components/split-button/split-button.component.tsx
@@ -155,7 +155,7 @@ export const SplitButton = ({
     onKeyDown: handleToggleButtonKeyDown,
     buttonType,
     size,
-    ...(!disabled && { onMouseEnter: showButtons }),
+    ...(!disabled && { onMouseEnter: showButtons, onClick: showButtons }),
   };
 
   function componentTags() {
@@ -249,7 +249,6 @@ export const SplitButton = ({
 
   return (
     <StyledSplitButton
-      aria-haspopup="true"
       onMouseLeave={hideButtonsIfTriggerNotFocused}
       onClick={handleClick}
       ref={splitButtonNode}
diff --git a/src/components/split-button/split-button.spec.tsx b/src/components/split-button/split-button.spec.tsx
index 106f5d322..f46a46af0 100644
--- a/src/components/split-button/split-button.spec.tsx
+++ b/src/components/split-button/split-button.spec.tsx
@@ -380,6 +380,41 @@ describe("SplitButton", () => {
       });
     });
 
+    describe("click dropdown toggle", () => {
+      beforeEach(() => {
+        wrapper = render(
+          {
+            text: "mainButton",
+          },
+          <Button>Second Button</Button>,
+          mount
+        );
+        toggle = wrapper.find(StyledSplitButtonToggle);
+      });
+
+      it("renders additional buttons", () => {
+        toggle.simulate("click");
+
+        expect(
+          wrapper.find("[data-element='additional-buttons']").exists()
+        ).toBe(true);
+      });
+
+      it("when disabled it does not render additional buttons", () => {
+        wrapper = render({ disabled: true }, singleButton, mount);
+        toggle = wrapper.find(StyledSplitButtonToggle);
+        toggle.simulate("click");
+
+        expect(
+          wrapper.find("[data-element='additional-buttons']").exists()
+        ).toBe(false);
+      });
+
+      afterEach(() => {
+        wrapper.unmount();
+      });
+    });
+
     describe("clicking a button", () => {
       const handleMainButton = jest.fn();
       const handleSecondButton = jest.fn();


Test patch:
diff --git a/src/components/multi-action-button/multi-action-button.test.js b/src/components/multi-action-button/multi-action-button.test.js
index 40c874b89..e739903e8 100644
--- a/src/components/multi-action-button/multi-action-button.test.js
+++ b/src/components/multi-action-button/multi-action-button.test.js
@@ -218,7 +218,7 @@ context("Tests for MultiActionButton component", () => {
   });
 
   describe("when nested inside of a Dialog component", () => {
-    it("should not close the Dialog when SplitButton is closed by pressing an escape key", () => {
+    it("should not close the Dialog when Multi Action Button is closed by pressing an escape key", () => {
       CypressMountWithProviders(<MultiActionNestedInDialog />);
       multiActionButtonComponent().trigger("mouseover");
       multiActionButtonList()
@@ -226,11 +226,11 @@ context("Tests for MultiActionButton component", () => {
         .should("have.text", "Example Button")
         .and("be.visible");
 
-      multiActionButtonComponent().type("{esc}");
+      multiActionButton().trigger("keyup", keyCode("Esc"));
       multiActionButtonListContainer().should("not.exist");
       alertDialogPreview().should("exist");
 
-      multiActionButtonComponent().type("{esc}");
+      multiActionButton().trigger("keyup", keyCode("Esc"));
       alertDialogPreview().should("not.exist");
     });
   });
@@ -518,6 +518,19 @@ describe.each(["Enter", "Space", "downarrow"])(
   }
 );
 
+describe("clicking the main button", () => {
+  it("should open the additional buttons", () => {
+    CypressMountWithProviders(<MultiActionButtonList />);
+
+    multiActionButton()
+      .eq(0)
+      .trigger("click")
+      .then(() => {
+        multiActionButtonList().should("be.visible");
+      });
+  });
+});
+
 // https://github.com/cypress-io/cypress/issues/21511
 describe("should check colors for MultiActionButton component", () => {
   it.each([
diff --git a/src/components/split-button/split-button.test.js b/src/components/split-button/split-button.test.js
index 461a1f4da..ab2c2f6db 100644
--- a/src/components/split-button/split-button.test.js
+++ b/src/components/split-button/split-button.test.js
@@ -169,6 +169,21 @@ context("Tests for Split Button component", () => {
     });
   });
 
+  describe("clicking the toggle button", () => {
+    it("should open the additional buttons", () => {
+      CypressMountWithProviders(<SplitButtonList />);
+
+      splitToggleButton()
+        .eq(0)
+        .trigger("click")
+        .then(() => {
+          additionalButton(0).should("be.visible");
+          additionalButton(1).should("be.visible");
+          additionalButton(2).should("be.visible");
+        });
+    });
+  });
+
   describe("pressing tab while SplitButton is open", () => {
     it("should move focus to next child button and to second SplitButton when end of list reached", () => {
       CypressMountWithProviders(