【发布时间】:2022-08-20 23:07:07
【问题描述】:
8月20日更新:@mark_reeder 和我在 Base Web Slack 上进行了后续聊天。 Mark 向我解释说,您可以将组件传递给 label 道具(而不是传递字符串)。所以现在,我没有用我自己的自定义组件覆盖 Option,而是将一个带有图标的自定义标签组件传递给 label。容易多了!再次感谢@mark_reeder。
8月16日更新:我接受了@mark_reeder 的回答。这解决了让焦点状态起作用的问题。但是,单击 \"Enter\" 以选择焦点元素仍然不起作用,我最终向正文添加了一个事件侦听器并执行了一些 kludegy 逻辑。我希望有人有更好的方法。
我是 Base Web 的新手。我建立了一个自定义的“更多选项”菜单(又名“烤肉串”菜单)。我希望选项具有图标,因此我对菜单组件中的选项进行了覆盖。看起来不错,但键盘绑定不再起作用。如果我注释掉覆盖,键盘绑定会起作用(但我会丢失图标)。
这是我的代码:
//MoreOptionsMenu.js
import React from \'react\'
import { StatefulPopover, PLACEMENT } from \'baseui/popover\'
import Overflow from \'baseui/icon/overflow\'
import { StatefulMenu } from \'baseui/menu\'
import IconOption from \'Components/Shared/IconOption/IconOption\'
import InvisibleButtonWrapper from \'Components/Shared/InvisibleButtonWrapper/InvisibleButtonWrapper\'
const MoreOptionsMenu = ({ items, placement = PLACEMENT.bottom, ariaLabel, id }) => {
return (
<StatefulPopover
content={({ close }) => (
<StatefulMenu
items={items}
overrides={{
Option: {
component: IconOption,
props: {
close,
ariaLabel,
id
}
},
List: {
style: ({ $theme }) => ({
borderTopLeftRadius: \'6px\',
borderTopRightRadius: \'6px\',
borderBottomLeftRadius: \'6px\',
borderBottomRightRadius: \'6px\',
border: `1px solid ${$theme.colors.lightGray}`,
})
}
}}
/>
)}
accessibilityType={\'tooltip\'}
placement={placement}
>
<InvisibleButtonWrapper>
<Overflow size={24} aria-label={ariaLabel} style={{ marginLeft: \'auto\', cursor: \'pointer\' }}/>
</InvisibleButtonWrapper>
</StatefulPopover>
)
}
export default MoreOptionsMenu
//IconOptions
import React, { forwardRef } from \'react\'
import { useStyletron } from \'baseui\'
import { stringToKebabCase } from \'Shared/Utilities\'
import InvisibleButtonWrapper from \'Components/Shared/InvisibleButtonWrapper/InvisibleButtonWrapper\'
const IconOption = forwardRef(( { close, item, ariaLabel, id }, ref) => {
const [css, theme] = useStyletron()
return (
<li
role=\'option\'
aria-disabled=\'false\'
aria-selected=\'false\'
id={stringToKebabCase(`${id}-${item.label}`)}
className={css({
display: \'flex\',
alignItems: \'center\',
padding: \'10px\',
cursor: \'pointer\',
\':hover\': {
outline: `${theme.colors.accent} solid 3px`
},
\':focus\': {
outline: `${theme.colors.accent} solid 3px`
},
\':active\': {
outline: `${theme.colors.accent} solid 3px`
},
\':nth-child(even)\': {
backgroundColor: theme.colors.lighterGray
}
})}
aria-labelledby={ariaLabel}
ref={ref}
onClick={() => {
typeof item.callback === \'function\' && item.callback()
close()
}}>
<InvisibleButtonWrapper>
{item.icon}
<span style={{ marginLeft: \'10px\' }}>{item.label}</span>
</InvisibleButtonWrapper>
</li>
)
})
export default IconOption
// InvisibleButtonWrapper.js
import { withStyle } from \'baseui\'
import { StyledBaseButton } from \'baseui/button\'
const InvisibleButtonWrapper = withStyle(StyledBaseButton, ({$theme}) => ({
paddingTop: 0,
paddingBottom: 0,
paddingLeft: 0,
paddingRight: 0,
color: `${$theme.colors.primaryA}`,
backgroundColor: \'inherit\',
\':hover\': {
color: `${$theme.colors.primaryA}`,
backgroundColor: \'inherit\',
}
}))
export default InvisibleButtonWrapper
这是sandbox所以你可以看到/玩代码
多做一些笔记,以期人们可能会遇到的问题。我使用 forwardRef 的原因是我收到关于函数组件无法接收引用的错误。无论我是否使用 forwardRef,键盘绑定都不起作用。 InvisibleButtonWrapper 旨在在不破坏样式的情况下使组件更易于访问。删除它似乎不会影响键盘绑定。
另外,是否有一种惯用的 Base Web 方式来做到这一点,我错过了?文档说“每个菜单项都有一个默认包含图标的选项,但这可以删除。”但是,没有关于如何使其工作的示例。在我创建自己的自定义组件之前,我尝试简单地向项目添加一个图标属性,但它没有呈现。
最新的文件更新,来自 mark_reeder 的修复和上述文档上的事件侦听器:
import React, { forwardRef, useEffect } from \'react\'
import { useStyletron } from \'baseui\'
import { stringToKebabCase } from \'Shared/Utilities\'
import InvisibleButtonWrapper from \'Components/Shared/InvisibleButtonWrapper/InvisibleButtonWrapper\'
const IconOption = forwardRef((props, ref) => {
const [css, theme] = useStyletron()
const { close, item, ariaLabel, id, $isHighlighted, $isFocused } = props
const handleKeyDown = ({ code }) => {
if (code === \'Enter\') {
document.querySelector(\"[data-iconoption=\'true\'][aria-selected=\'true\']\").click()
}
}
useEffect(() => {
document.addEventListener(\'keydown\', handleKeyDown)
return () => {
document.removeEventListener(\'keydown\', handleKeyDown)
}
}, [])
return (
<li
data-iconoption={\'true\'}
tabIndex={0}
role=\'option\'
aria-selected={props[\'aria-selected\'] ? \'true\' : \'false\'}
id={stringToKebabCase(`${id}-${item.label}`)}
className={css({
backgroundColor: $isHighlighted ? theme.colors.lighterGray : theme.colors.white,
display: \'flex\',
alignItems: \'center\',
padding: \'10px\',
cursor: \'pointer\',
\':hover\': {
backgroundColor: theme.colors.lighterGray
},
\':focus\': {
backgroundColor: theme.colors.lighterGray
},
})}
aria-labelledby={ariaLabel}
ref={ref}
onClick={() => {
typeof item.callback === \'function\' && item.callback()
close()
}}>
<InvisibleButtonWrapper>
{item.icon}
<span style={{ marginLeft: \'10px\' }}>{item.label}</span>
</InvisibleButtonWrapper>
</li>
)
})
export default IconOption
标签: reactjs accessibility baseweb