Skip to content

Commit

Permalink
feat: splitButton accessibility improvements (#1458)
Browse files Browse the repository at this point in the history
* feat: splitButton accessibility improvements

* feat: splitButton accessibility improvements

* feat: splitButton accessibility improvements

* refactor: apply code review comments (pairing session)

---------

Co-authored-by: Mozafar Haider <[email protected]>
  • Loading branch information
Chisomchima and kabaros authored Mar 19, 2024
1 parent f11eabb commit 51a1b14
Show file tree
Hide file tree
Showing 2 changed files with 108 additions and 1 deletion.
24 changes: 23 additions & 1 deletion components/button/src/split-button/split-button.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import PropTypes from 'prop-types'
import React, { Component } from 'react'
import css from 'styled-jsx/css'
import { Button } from '../index.js'
import i18n from '../locales/index.js'

const rightButton = css.resolve`
button {
Expand All @@ -18,8 +19,25 @@ class SplitButton extends Component {
state = {
open: false,
}

anchorRef = React.createRef()

componentDidMount() {
document.addEventListener('keydown', this.handleKeyDown)
}

componentWillUnmount() {
document.removeEventListener('keydown', this.handleKeyDown)
}
handleKeyDown = (event) => {
event.preventDefault()
if (event.key === 'Escape' && this.state.open) {
event.stopPropagation()
this.setState({ open: false })
this.anchorRef.current && this.anchorRef.current.focus()
}
}

onClick = (payload, event) => {
if (this.props.onClick) {
this.props.onClick(
Expand All @@ -33,7 +51,9 @@ class SplitButton extends Component {
}
}

onToggle = () => this.setState({ open: !this.state.open })
onToggle = () => {
this.setState((prevState) => ({ open: !prevState.open }))
}

render() {
const { open } = this.state
Expand Down Expand Up @@ -94,6 +114,8 @@ class SplitButton extends Component {
tabIndex={tabIndex}
className={cx(className, rightButton.className)}
dataTest={`${dataTest}-toggle`}
title={i18n.t('Toggle dropdown')}
aria-label={i18n.t('Toggle dropdown')}
>
{arrow}
</Button>
Expand Down
85 changes: 85 additions & 0 deletions components/button/src/split-button/split-button.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import { render, fireEvent, cleanup, waitFor } from '@testing-library/react'
import React from 'react'
import '@testing-library/jest-dom/extend-expect'
import { SplitButton } from './split-button.js'

describe('SplitButton', () => {
afterEach(cleanup)

it('renders button with children', () => {
const { getByText } = render(<SplitButton>Click me</SplitButton>)
expect(getByText('Click me')).toBeInTheDocument()
})

it('toggles dropdown when left button is clicked', () => {
const { getByTestId, queryByTestId } = render(<SplitButton />)
const toggleButton = getByTestId('dhis2-uicore-splitbutton-toggle')

fireEvent.click(toggleButton)
expect(
queryByTestId('dhis2-uicore-splitbutton-menu')
).toBeInTheDocument()

fireEvent.click(toggleButton)
expect(
queryByTestId('dhis2-uicore-splitbutton-menu')
).not.toBeInTheDocument()
})

it('renders dropdown content when open is true', () => {
const { getByTestId } = render(
<SplitButton component={<div>Dropdown Content</div>} />
)

const toggleButton = getByTestId('dhis2-uicore-splitbutton-toggle')
fireEvent.click(toggleButton)

expect(getByTestId('dhis2-uicore-splitbutton-menu')).toBeInTheDocument()
})

it("does not close dropdown 'Enter' key is pressed", async () => {
const { getByTestId } = render(
<SplitButton component={<div>Dropdown Content</div>} />
)

const toggleButton = getByTestId('dhis2-uicore-splitbutton-toggle')
fireEvent.click(toggleButton)
expect(getByTestId('dhis2-uicore-splitbutton-menu')).toBeInTheDocument()

fireEvent.keyDown(document, { key: 'Enter' })

// Use waitFor to wait for the DOM to update
await waitFor(() => {
expect(
getByTestId('dhis2-uicore-splitbutton-menu')
).toBeInTheDocument()
})
})

it('closes dropdown when escape key is pressed', async () => {
const { getByTestId, queryByTestId } = render(
<SplitButton component={<div>Dropdown Content</div>} />
)

const toggleButton = getByTestId('dhis2-uicore-splitbutton-toggle')
fireEvent.click(toggleButton)
expect(getByTestId('dhis2-uicore-splitbutton-menu')).toBeInTheDocument()

fireEvent.keyDown(document, { key: 'Escape' })

// Use waitFor to wait for the DOM to update
await waitFor(() => {
expect(
queryByTestId('dhis2-uicore-splitbutton-menu')
).not.toBeInTheDocument()
})
})

it('adds title and aria-label attributes to the right button', () => {
const { getByTestId } = render(<SplitButton />)
const toggleButton = getByTestId('dhis2-uicore-splitbutton-toggle')

expect(toggleButton).toHaveAttribute('title', 'Toggle dropdown')
expect(toggleButton).toHaveAttribute('aria-label', 'Toggle dropdown')
})
})

0 comments on commit 51a1b14

Please sign in to comment.