Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[issue-4] - Fix accesibility issues AutoSuggest address component #5

Open
wants to merge 38 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
f91425b
Changed SLIDEUP_TIMEOUT to 3 seconds in Notification (#2743)
SireeKoolenWijkstra Nov 6, 2023
afa2ae6
[feature-5530]: Add zoeken op locatiekaart on desktop (#2737)
OscarBakker Nov 6, 2023
93440e6
Remove political message from leaflet map (#2744)
OscarBakker Nov 6, 2023
7266b2a
[feat-5471]: Refactor FilterForm to TS (#2746)
vdegraaf Nov 6, 2023
14f44d0
Text change (#2747)
SireeKoolenWijkstra Nov 7, 2023
0007b1e
[bugfix]: implement useWatch to see if changes occur in inputfield of…
SireeKoolenWijkstra Nov 7, 2023
98fdb40
[feat-5471]: filter accordion (#2748)
vdegraaf Nov 8, 2023
55e304a
Changed order of components in CategoryForm (#2749)
SireeKoolenWijkstra Nov 8, 2023
1986f83
Update permissions (#2741)
SireeKoolenWijkstra Nov 8, 2023
cc20a52
[chore-5471]: Change label color with newDesignDystem prop (#2750)
vdegraaf Nov 9, 2023
9827268
Set showStandardTextAdminV1 in app.amsterdam.json to false (#2751)
SireeKoolenWijkstra Nov 13, 2023
a3568a1
[fix]:standard texts query (#2753)
vdegraaf Nov 13, 2023
8618f8b
Changed <Fragment> to <div> so that title is immediately behind the r…
SireeKoolenWijkstra Nov 14, 2023
d7b2cd2
[feat-5470]: Order incident table with headers instead of dropdown (#…
OscarBakker Nov 15, 2023
4ba3516
[feat-5459]: Put search bar to top menu (#2755)
vdegraaf Nov 16, 2023
b1179f3
Fix success notification message en unnecessary calls/actions (#2756)
vdegraaf Nov 20, 2023
30d40e3
Remove double feature flag (#2759)
vdegraaf Nov 20, 2023
1b130ce
Removed tests that concern changes in PDOKAutosuggest values. PDOKAut…
SireeKoolenWijkstra Nov 22, 2023
af91429
Improve accesibility of address autocomplete, add correct aria labels…
justiandevs Nov 23, 2023
8a6c4d8
[Feature-5438]: lijstweergave selecteerbare objecten (#2757)
OscarBakker Nov 23, 2023
89289dc
SuggestList: Communicate error state to user when there is no valid a…
justiandevs Nov 23, 2023
c72607a
Add: Error state to PDOkAutoSuggest and Close Map validation logic to…
justiandevs Nov 23, 2023
f03d3c7
Add: add border to element with error
justiandevs Nov 23, 2023
3df378e
Fix: tests for PDOK address selector
justiandevs Nov 27, 2023
5ab39d1
Fix: Detail Panel test
justiandevs Nov 27, 2023
1e9b45e
Improve accesibility of address autocomplete, add correct aria labels…
justiandevs Nov 23, 2023
8ccd9cf
SuggestList: Communicate error state to user when there is no valid a…
justiandevs Nov 23, 2023
6d0c769
Add: Error state to PDOkAutoSuggest and Close Map validation logic to…
justiandevs Nov 23, 2023
4b504a0
Add: add border to element with error
justiandevs Nov 23, 2023
c8db096
Fix: tests for PDOK address selector
justiandevs Nov 27, 2023
c55a1b1
Fix: Detail Panel test
justiandevs Nov 27, 2023
8115650
Rebase: amsterdam/main
justiandevs Nov 27, 2023
ad04a75
Merge remote-tracking branch 'delta10/fix-accesibility-issues-address…
justiandevs Nov 27, 2023
653d63f
Fix: set show showSelector default to false
justiandevs Nov 28, 2023
9ef59f1
Fix: remove error state for now
justiandevs Nov 28, 2023
49bd733
Fix: remove error state for now
justiandevs Nov 28, 2023
124b71d
Merge remote-tracking branch 'delta10/fix-accesibility-issues-address…
justiandevs Nov 28, 2023
6cb2eb1
Add: spellCheck = false to AutoSuggest.tsx
justiandevs Nov 29, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app.amsterdam.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"reporterMailHandledNegativeContactEnabled": true,
"showMainCategories": true,
"showStandardTextAdminV2": true,
"showStandardTextAdminV1": false,
"showThorButton": true,
"showVulaanControls": true,
"useProjectenSignalType": false,
Expand Down
51 changes: 51 additions & 0 deletions src/components/Accordion/Accordion.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// SPDX-License-Identifier: MPL-2.0
// Copyright (C) 2023 Gemeente Amsterdam
import { render, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'

import { Accordion } from './Accordion'

describe('Accordion', () => {
const mockOnToggle = jest.fn()
const props = {
id: 'testId',
title: 'Test Title',
count: 5,
onToggle: mockOnToggle,
children: <div>Test Content</div>,
}

afterEach(() => {
jest.resetAllMocks()
})

it('should render title and count', () => {
render(<Accordion {...props} />)

expect(screen.getByText(/Test Title/)).toBeInTheDocument()
expect(screen.getByText(/(5)/)).toBeInTheDocument()
})

it('should not render count', () => {
render(<Accordion {...props} count="" />)
expect(screen.getByText(/Test Title/)).toBeInTheDocument()
expect(screen.queryByText(/(5)/)).not.toBeInTheDocument()
})

it('should call onToggle and render children when button is clicked', () => {
render(<Accordion {...props} />)

userEvent.click(screen.getByText(/Test Title/))
expect(mockOnToggle).toHaveBeenCalledWith(true)
expect(screen.getByText(/Test Content/)).toBeInTheDocument()
})

it('should toggle open state when button is clicked twice', () => {
render(<Accordion {...props} />)

const button = screen.getByText(/Test Title/)
userEvent.click(button)
userEvent.click(button)
expect(mockOnToggle).toHaveBeenCalledWith(false)
})
})
50 changes: 50 additions & 0 deletions src/components/Accordion/Accordion.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/* SPDX-License-Identifier: MPL-2.0 */
/* Copyright (C) 2023 Gemeente Amsterdam */
import { useCallback, useState } from 'react'

import { ChevronDown } from '@amsterdam/asc-assets'

import { Button, ButtonContent, Content, Wrapper, Border } from './styled'

type Props = {
id: string
title: string
count: number | string
onToggle?: (open: boolean) => void
children: React.ReactNode
}

export const Accordion = ({ children, count, title, id, onToggle }: Props) => {
const [open, setOpen] = useState(false)

const handleClick = useCallback(() => {
if (onToggle) {
onToggle(!open)
}
setOpen(!open)
}, [open, onToggle])

return (
<Wrapper isOpen={open}>
<Border isOpen={open}>
<Button
aria-controls={id}
aria-expanded={open}
type="button"
variant="textButton"
isOpen={open}
onClick={handleClick}
>
<ButtonContent>
{title}
{count ? ` (${count})` : ''}
<ChevronDown width={20} height={20} />
</ButtonContent>
</Button>
<Content isOpen={open} aria-labelledby={`label-${id}`} id={id}>
{children}
</Content>
</Border>
</Wrapper>
)
}
1 change: 1 addition & 0 deletions src/components/Accordion/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { Accordion } from './Accordion'
64 changes: 64 additions & 0 deletions src/components/Accordion/styled.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/* SPDX-License-Identifier: MPL-2.0 */
/* Copyright (C) 2023 Gemeente Amsterdam */
import { Button as AscButton, themeSpacing } from '@amsterdam/asc-ui'
import styled from 'styled-components'

const darkBlue = '#102e62'
export interface Props {
isOpen?: boolean
}

export const Wrapper = styled.div<Props>`
border: ${({ isOpen }) =>
isOpen ? `1px solid ${darkBlue}` : '1px solid transparent'};
margin-bottom: 4px;

&:hover {
border: 1px solid ${darkBlue};
}
`

export const Border = styled.div<Props>`
border: 1px solid transparent;

&:hover {
border: 1px solid ${darkBlue};
}
`

export const Button = styled(AscButton)<Props>`
width: 100%;
box-sizing: border-box;
font-size: 1.125rem;
font-family: 'Amsterdam Sans', sans-serif;
svg {
transform: rotate(${({ isOpen }) => (isOpen ? '180deg' : '0deg')});
transition: transform 0.3s ease;
}

&:hover {
color: ${darkBlue};
}
`

export const ButtonContent = styled.div`
box-sizing: border-box;
display: flex;
justify-content: space-between;
padding: ${themeSpacing(3, 4)};
text-align: left;
white-space: normal;
width: 100%;

&:hover {
svg path {
fill: ${darkBlue};
}
}
`

export const Content = styled.div<Props>`
transition: border-color 0.1s ease-in-out;
padding: ${themeSpacing(0, 4)};
display: ${({ isOpen }) => !isOpen && 'none'};
`
50 changes: 25 additions & 25 deletions src/components/AutoSuggest/AutoSuggest.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const mockResponse = JSON.stringify(JSONResponse)
const numOptionsDeterminer: AutoSuggestProps['numOptionsDeterminer'] = (data) =>
data?.response?.docs?.length || 0
const formatResponse: AutoSuggestProps['formatResponse'] = (requestData) =>
requestData?.response?.docs.map((result) => {
requestData?.response?.docs.map((result: any) => {
const { id, weergavenaam } = result
return {
id,
Expand Down Expand Up @@ -73,7 +73,7 @@ describe('src/components/AutoSuggest', () => {

expect(screen.getByRole('combobox')).toBeInTheDocument()

const input = screen.getByRole('textbox')
const input = screen.getByRole('combobox')
expect(input).toBeInTheDocument()
expect(input.getAttribute('aria-autocomplete')).toEqual('list')
expect(input.getAttribute('id')).toBe('')
Expand All @@ -91,29 +91,29 @@ describe('src/components/AutoSuggest', () => {

userEvent.click(searchInput)

expect(screen.getByRole('textbox')).toHaveFocus()
expect(screen.getByRole('combobox')).toHaveFocus()
})

it('should set an id on the input field', () => {
const id = 'id'
render(withAppContext(<AutoSuggest {...{ ...props, id }} />))

const input = screen.getByRole('textbox')
const input = screen.getByRole('combobox')
expect(input).toBeInTheDocument()
expect(input.getAttribute('id')).toEqual(id)
})

it('should disable the input field', () => {
render(withAppContext(<AutoSuggest {...{ ...props, disabled: true }} />))

const input = screen.getByRole('textbox')
const input = screen.getByRole('combobox')
expect(input).toBeInTheDocument()
expect(input.hasAttribute('disabled')).toBe(true)
})

it('should request external service', async () => {
render(withAppContext(<AutoSuggest {...props} />))
const input = screen.getByRole('textbox')
const input = screen.getByRole('combobox')

userEvent.type(input, 'A')

Expand Down Expand Up @@ -160,7 +160,7 @@ describe('src/components/AutoSuggest', () => {

it('should request external service with auth when configured', async () => {
render(withAppContext(<AutoSuggest {...props} includeAuthHeaders={true} />))
const input = screen.getByRole('textbox')
const input = screen.getByRole('combobox')
userEvent.type(input, 'Ams')

act(() => {
Expand All @@ -183,7 +183,7 @@ describe('src/components/AutoSuggest', () => {

it('should show a value without sending a request to the external service', async () => {
const { rerender } = render(withAppContext(<AutoSuggest {...props} />))
const input = screen.getByRole('textbox') as HTMLInputElement
const input = screen.getByRole('combobox') as HTMLInputElement

await screen.findByTestId('auto-suggest')

Expand All @@ -206,7 +206,7 @@ describe('src/components/AutoSuggest', () => {

it('should render a list of suggestions', async () => {
render(withAppContext(<AutoSuggest {...props} />))
const input = screen.getByRole('textbox')
const input = screen.getByRole('combobox')

expect(screen.queryByTestId('suggest-list')).not.toBeInTheDocument()

Expand All @@ -221,7 +221,7 @@ describe('src/components/AutoSuggest', () => {
describe('keyboard navigation', () => {
it('ArrowUp key', async () => {
render(withAppContext(<AutoSuggest {...props} />))
const input = screen.getByRole('textbox')
const input = screen.getByRole('combobox')

userEvent.type(input, '{ArrowUp}')

Expand Down Expand Up @@ -250,7 +250,7 @@ describe('src/components/AutoSuggest', () => {

it('ArrowDown key', async () => {
render(withAppContext(<AutoSuggest {...props} />))
const input = screen.getByRole('textbox') as HTMLInputElement
const input = screen.getByRole('combobox') as HTMLInputElement

await waitFor(() => {
expect(input.getAttribute('aria-activedescendant')).toBeFalsy()
Expand Down Expand Up @@ -282,7 +282,7 @@ describe('src/components/AutoSuggest', () => {

it('ArrowUp and ArrowDown cycle', async () => {
render(withAppContext(<AutoSuggest {...props} />))
const input = screen.getByRole('textbox')
const input = screen.getByRole('combobox')

expect(input.getAttribute('aria-activedescendant')).toBeFalsy()

Expand Down Expand Up @@ -328,7 +328,7 @@ describe('src/components/AutoSuggest', () => {
it('Esc', async () => {
const onClear = jest.fn()
render(withAppContext(<AutoSuggest {...props} onClear={onClear} />))
const input = screen.getByRole('textbox') as HTMLInputElement
const input = screen.getByRole('combobox') as HTMLInputElement

await waitFor(() => {
userEvent.type(input, 'Boom')
Expand Down Expand Up @@ -373,7 +373,7 @@ describe('src/components/AutoSuggest', () => {
withAppContext(<AutoSuggest {...props} />)
)

const input = screen.getByRole('textbox') as HTMLInputElement
const input = screen.getByRole('combobox') as HTMLInputElement

await waitFor(() => {
userEvent.type(input, 'Boom')
Expand Down Expand Up @@ -413,7 +413,7 @@ describe('src/components/AutoSuggest', () => {

it('Home', async () => {
render(withAppContext(<AutoSuggest {...props} />))
const input = screen.getByRole('textbox')
const input = screen.getByRole('combobox')

await waitFor(() => {
userEvent.type(input, 'Niezel')
Expand Down Expand Up @@ -447,7 +447,7 @@ describe('src/components/AutoSuggest', () => {

it('End', async () => {
render(withAppContext(<AutoSuggest {...props} />))
const input = screen.getByRole('textbox')
const input = screen.getByRole('combobox')
const value = 'Midden'

await waitFor(() => {
Expand Down Expand Up @@ -541,7 +541,7 @@ describe('src/components/AutoSuggest', () => {

it('Any key (yes, such a key exists)', async () => {
render(withAppContext(<AutoSuggest {...props} />))
const input = screen.getByRole('textbox')
const input = screen.getByRole('combobox')

await waitFor(() => {
userEvent.type(input, 'Meeuwenlaan')
Expand All @@ -567,7 +567,7 @@ describe('src/components/AutoSuggest', () => {

it('should call onSelect on item click', async () => {
render(withAppContext(<AutoSuggest {...props} />))
const input = screen.getByRole('textbox') as HTMLInputElement
const input = screen.getByRole('combobox') as HTMLInputElement

await waitFor(() => {
userEvent.type(input, 'Rembrandt')
Expand Down Expand Up @@ -600,7 +600,7 @@ describe('src/components/AutoSuggest', () => {

expect(screen.queryByTestId('clear-input')).not.toBeInTheDocument()

const input = screen.getByRole('textbox')
const input = screen.getByRole('combobox')

await waitFor(() => {
userEvent.type(input, 'Rembrandt')
Expand All @@ -625,7 +625,7 @@ describe('src/components/AutoSuggest', () => {
it('calls onClear', async () => {
const onClear = jest.fn()
render(withAppContext(<AutoSuggest {...props} onClear={onClear} />))
const input = screen.getByRole('textbox')
const input = screen.getByRole('combobox')

await waitFor(() => {
userEvent.type(input, 'Rembrandt')
Expand Down Expand Up @@ -666,7 +666,7 @@ describe('src/components/AutoSuggest', () => {

expect(onClear).toHaveBeenCalled()

expect(screen.getByRole('textbox')).toHaveFocus()
expect(screen.getByRole('combobox')).toHaveFocus()
})

it('focuses the input on clear', async () => {
Expand All @@ -686,14 +686,14 @@ describe('src/components/AutoSuggest', () => {

userEvent.click(screen.getByTestId('clear-input'))

expect(screen.getByRole('textbox')).toHaveFocus()
expect(screen.getByRole('combobox')).toHaveFocus()
})

it('calls onData', async () => {
const onData = jest.fn()

render(withAppContext(<AutoSuggest {...props} onData={onData} />))
const input = screen.getByRole('textbox')
const input = screen.getByRole('combobox')

userEvent.type(input, 'Rembrandt')

Expand All @@ -710,7 +710,7 @@ describe('src/components/AutoSuggest', () => {

it('should work without onClear defined', async () => {
render(withAppContext(<AutoSuggest {...props} />))
const input = screen.getByRole('textbox')
const input = screen.getByRole('combobox')

userEvent.type(input, 'Rembrandt')

Expand Down Expand Up @@ -738,7 +738,7 @@ describe('src/components/AutoSuggest', () => {

expect(onFocus).not.toHaveBeenCalled()

fireEvent.focus(screen.getByRole('textbox'))
fireEvent.focus(screen.getByRole('combobox'))

expect(onFocus).toHaveBeenCalled()
})
Expand Down
Loading
Loading