Skip to content

Commit

Permalink
fix: AccordionPanelのkeydownイベントリスナーをTriggerに移動
Browse files Browse the repository at this point in the history
  • Loading branch information
neet committed Dec 26, 2024
1 parent 6fead5e commit c145d0f
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 52 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { userEvent } from '@storybook/test'
import { render, screen } from '@testing-library/react'
import React from 'react'

import { Fieldset } from '../Fieldset'
import { RadioButton } from '../RadioButton'

import { AccordionPanel } from './AccordionPanel'
import { AccordionPanelContent } from './AccordionPanelContent'
import { AccordionPanelItem } from './AccordionPanelItem'
import { AccordionPanelTrigger } from './AccordionPanelTrigger'

describe('AccordionPanel', () => {
test('アコーディオン内に配置したラジオボタンをキーボード操作できる', async () => {
render(
<form>
<AccordionPanel>
<AccordionPanelItem name="accordion-panel-1">
<AccordionPanelTrigger>アコーディオンパネル1</AccordionPanelTrigger>
<AccordionPanelContent>
<Fieldset title="ラジオボタン" innerMargin={0.5}>
<RadioButton name="radio1">ラジオボタン1</RadioButton>
<RadioButton name="radio1">ラジオボタン2</RadioButton>
</Fieldset>
</AccordionPanelContent>
</AccordionPanelItem>
</AccordionPanel>
</form>,
)

await userEvent.click(screen.getByRole('button', { name: 'アコーディオンパネル1' }))

await userEvent.keyboard('[Tab]')
expect(screen.getByRole('radio', { name: 'ラジオボタン1' })).toHaveFocus()

await userEvent.keyboard('[ArrowRight]')
expect(screen.getByRole('radio', { name: 'ラジオボタン2' })).toHaveFocus()

await userEvent.keyboard('[ArrowLeft]')
expect(screen.getByRole('radio', { name: 'ラジオボタン1' })).toHaveFocus()
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,7 @@ import { tv } from 'tailwind-variants'

import { flatArrayToMap } from '../../libs/map'

import {
focusFirstSibling,
focusLastSibling,
focusNextSibling,
focusPreviousSibling,
getNewExpandedItems,
keycodes,
} from './accordionPanelHelper'
import { getNewExpandedItems } from './accordionPanelHelper'

type Props = PropsWithChildren<{
/** アイコンの左右位置 */
Expand Down Expand Up @@ -71,40 +64,6 @@ export const AccordionPanel: React.FC<Props & ElementProps> = ({
[expandableMultiply, expandedItems],
)

const handleKeyPress = (event: React.KeyboardEvent<HTMLDivElement>): void => {
if (!parentRef?.current) {
return
}

const keyCode = event.keyCode
const item = event.target as HTMLElement

switch (keyCode) {
case keycodes.HOME: {
event.preventDefault()
focusFirstSibling(parentRef.current)
break
}
case keycodes.END: {
event.preventDefault()
focusLastSibling(parentRef.current)
break
}
case keycodes.LEFT:
case keycodes.UP: {
event.preventDefault()
focusPreviousSibling(item, parentRef.current)
break
}
case keycodes.RIGHT:
case keycodes.DOWN: {
event.preventDefault()
focusNextSibling(item, parentRef.current)
break
}
}
}

useEffect(() => {
if (defaultExpanded.length > 0) setExpanded(flatArrayToMap(defaultExpanded))
}, [defaultExpanded])
Expand All @@ -121,13 +80,7 @@ export const AccordionPanel: React.FC<Props & ElementProps> = ({
}}
>
{/* eslint-disable-next-line smarthr/a11y-delegate-element-has-role-presentation */}
<div
{...props}
className={styles}
ref={parentRef}
onKeyDown={handleKeyPress}
role="presentation"
/>
<div {...props} className={styles} ref={parentRef} role="presentation" />
</AccordionPanelContext.Provider>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,14 @@ import { TextProps } from '../Text'

import { AccordionPanelContext } from './AccordionPanel'
import { AccordionPanelItemContext } from './AccordionPanelItem'
import { getNewExpandedItems } from './accordionPanelHelper'
import {
focusFirstSibling,
focusLastSibling,
focusNextSibling,
focusPreviousSibling,
getNewExpandedItems,
keycodes,
} from './accordionPanelHelper'

type Props = PropsWithChildren<{
/** ヘッダ部分のテキストのスタイル */
Expand Down Expand Up @@ -70,8 +77,14 @@ export const AccordionPanelTrigger: FC<Props & ElementProps> = ({
}
}, [className])
const { name } = useContext(AccordionPanelItemContext)
const { iconPosition, expandedItems, onClickTrigger, onClickProps, expandableMultiply } =
useContext(AccordionPanelContext)
const {
iconPosition,
expandedItems,
onClickTrigger,
onClickProps,
expandableMultiply,
parentRef,
} = useContext(AccordionPanelContext)

const isExpanded = getIsInclude(expandedItems, name)

Expand All @@ -89,6 +102,40 @@ export const AccordionPanelTrigger: FC<Props & ElementProps> = ({
}
}, [onClickTrigger, name, isExpanded, onClickProps, expandedItems, expandableMultiply])

const handleKeyPress = (event: React.KeyboardEvent<HTMLButtonElement>): void => {
if (!parentRef?.current) {
return
}

const keyCode = event.keyCode
const item = event.target as HTMLElement

switch (keyCode) {
case keycodes.HOME: {
event.preventDefault()
focusFirstSibling(parentRef.current)
break
}
case keycodes.END: {
event.preventDefault()
focusLastSibling(parentRef.current)
break
}
case keycodes.LEFT:
case keycodes.UP: {
event.preventDefault()
focusPreviousSibling(item, parentRef.current)
break
}
case keycodes.RIGHT:
case keycodes.DOWN: {
event.preventDefault()
focusNextSibling(item, parentRef.current)
break
}
}
}

return (
// eslint-disable-next-line smarthr/a11y-heading-in-sectioning-content
<Heading tag={headingTag} type={headingType}>
Expand All @@ -98,6 +145,7 @@ export const AccordionPanelTrigger: FC<Props & ElementProps> = ({
aria-expanded={isExpanded}
aria-controls={`${name}-content`}
onClick={handleClick}
onKeyDown={handleKeyPress}
className={buttonStyle}
data-component="AccordionHeaderButton"
type="button"
Expand Down

0 comments on commit c145d0f

Please sign in to comment.