Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
a09b8f3
Change deprecated/ActionList semantics
Jun 23, 2022
5dceefa
Remove item selection via Enter key
Jun 23, 2022
f00baae
Handle focus on deprecated/ActionList
Jun 23, 2022
5e0c3aa
Adapt deprecated/ActionMenu prop
Jun 23, 2022
a7e3b74
Update deprecated/ActionList tests and stories
Jun 23, 2022
bc30a7b
Update deprecated/ActionList docs
Jun 23, 2022
1fa7658
Remove focusZone from the FilteredActionList component
Jun 23, 2022
2ab0a6c
Add sr-only description for input in the FilteredActionList component
Jun 23, 2022
19afe42
Adapt SelectPanel: semantics, visual layout, add title, close button,…
Jun 23, 2022
94b7ef0
Update SelectPanel test snap
Jun 23, 2022
d0d1eca
Update deprecated/ActionList axe test
Jun 23, 2022
f851e04
Update deprecated/ActionList axe test
Jun 23, 2022
f29a531
Reduce padding in SelectPanel header
Jun 23, 2022
dfd8096
Delete commented code
Jun 23, 2022
2dbe48b
Update stories, Add ESC reset functionality
Jun 23, 2022
d28b90d
Add changeset (breaking change)
Jun 27, 2022
4c54d8a
Preselect items on the SelectPanel docs that aren't the first ones
hectahertz Jun 27, 2022
81bd886
Use Heading instead of h1 on SelectPanel
hectahertz Jun 27, 2022
9fcaee3
Don't use selected items as the SelectPanel anchor label
hectahertz Jun 27, 2022
db16c68
Replace custom SrOnly with VisuallyHidden
hectahertz Jun 27, 2022
a77f78c
Make the SelectPanel example dimensions larger
hectahertz Jun 27, 2022
7d01c0d
Support setting the selected items asyncronously
hectahertz Jun 27, 2022
422d451
Merge branch 'main' into primer/issues/1021/reeact-select-panel
hectahertz Jun 28, 2022
0144a21
Fix new select panel issues (#2147)
camchenry Jun 28, 2022
f6f2043
Remove unsupported PageUpDown bindkeys from useFocusZone
hectahertz Jul 1, 2022
9ac7b32
Merge branch 'main' into primer/issues/1021/reeact-select-panel
hectahertz Jul 1, 2022
a304177
Remove console.debug
hectahertz Jul 1, 2022
2cff0c0
Merge branch 'main' into primer/issues/1021/reeact-select-panel
hectahertz Aug 18, 2022
e3f07a6
Make `title` and `inputLabel` optional with defaults
hectahertz Aug 18, 2022
ce4715d
Remove unused prop
hectahertz Aug 18, 2022
2669c4f
Add a placeholder prop for the search input
hectahertz Aug 18, 2022
a838425
Make footer buttons smaller
hectahertz Aug 18, 2022
a4d209e
Use `ButtonClose`
hectahertz Aug 18, 2022
1ae651a
Better default title for multiselect `SelectPanel`
hectahertz Aug 19, 2022
76c576e
Merge branch 'main' into primer/issues/1021/reeact-select-panel
hectahertz Aug 22, 2022
e71bad8
Merge branch 'main' into primer/issues/1021/reeact-select-panel
hectahertz Aug 23, 2022
266eab4
Fix lint warnings
hectahertz Aug 23, 2022
8f445ab
Merge branch 'primer/issues/1021/reeact-select-panel' of https://gith…
hectahertz Aug 23, 2022
d4136cc
Merge branch 'main' into primer/issues/1021/reeact-select-panel
hectahertz Aug 24, 2022
ee5f515
Merge branch 'main' into primer/issues/1021/reeact-select-panel
hectahertz Aug 25, 2022
e6f6297
Fix the AutocompleteMenu tests
hectahertz Aug 25, 2022
a591223
Merge branch 'primer/issues/1021/reeact-select-panel' of https://gith…
hectahertz Aug 25, 2022
9c7e894
Fix lint error
hectahertz Aug 25, 2022
54db5ef
Fix MarkdownEditor tests, remove one for old behavior
hectahertz Aug 25, 2022
b828d90
Merge branch 'main' into primer/issues/1021/reeact-select-panel
hectahertz Aug 25, 2022
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
5 changes: 5 additions & 0 deletions .changeset/grumpy-carrots-admire.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@primer/react': minor
---

Accessibility fixes for SelectPanel.
13 changes: 7 additions & 6 deletions docs/content/SelectPanel.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -37,27 +37,28 @@ const items = [
]

function DemoComponent() {
const [selected, setSelected] = React.useState([items[0], items[1]])
const [selected, setSelected] = React.useState([items[2], items[4]])
const [filter, setFilter] = React.useState('')
const filteredItems = items.filter(item => item.text.toLowerCase().startsWith(filter.toLowerCase()))
const [open, setOpen] = React.useState(false)

return (
<SelectPanel
renderAnchor={({children, 'aria-labelledby': ariaLabelledBy, ...anchorProps}) => (
<Button trailingIcon={TriangleDownIcon} aria-labelledby={` ${ariaLabelledBy}`} {...anchorProps}>
{children || 'Select Labels'}
renderAnchor={({...anchorProps}) => (
<Button trailingIcon={TriangleDownIcon} {...anchorProps}>
Select Labels
</Button>
)}
placeholderText="Filter Labels"
title="Select Items"
inputLabel="Select Items"
open={open}
onOpenChange={setOpen}
items={filteredItems}
selected={selected}
onSelectedChange={setSelected}
onFilterChange={setFilter}
showItemDividers={true}
overlayProps={{width: 'small', height: 'xsmall'}}
overlayProps={{width: 'medium', height: 'medium'}}
/>
)
}
Expand Down
52 changes: 31 additions & 21 deletions docs/content/deprecated/ActionList.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -14,25 +14,26 @@ Use [new version of ActionList](/ActionList) with composable API, design updates

```jsx
<ActionList
role="listbox"
items={[
{text: 'New file'},
{text: 'Copy link'},
{text: 'Edit file'},
{text: 'New file', role: 'option'},
{text: 'Copy link', role: 'option'},
{text: 'Edit file', role: 'option'},
ActionList.Divider,
{text: 'Delete file', variant: 'danger'}
{text: 'Delete file', variant: 'danger', role: 'option'}
]}
/>
```

**After**

```jsx
<ActionList>
<ActionList.Item>New file</ActionList.Item>
<ActionList.Item>Copy link</ActionList.Item>
<ActionList.Item>Edit file</ActionList.Item>
<ActionList role="listbox">
<ActionList.Item role="option">New file</ActionList.Item>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should role="option" be the default value?

<ActionList.Item role="option">Copy link</ActionList.Item>
<ActionList.Item role="option">Edit file</ActionList.Item>
<ActionList.Divider />
<ActionList.Item variant="danger">Delete file</ActionList.Item>
<ActionList.Item variant="danger" role="option">Delete file</ActionList.Item>
</ActionList>
```

Expand All @@ -46,12 +47,13 @@ import {ActionList} from '@primer/react/deprecated'

```jsx live deprecated
<ActionList
role="listbox"
items={[
{text: 'New file'},
{text: 'New file', role: 'option'},
ActionList.Divider,
{text: 'Copy link'},
{text: 'Edit file'},
{text: 'Delete file', variant: 'danger'}
{text: 'Copy link', role: 'option'},
{text: 'Edit file', role: 'option'},
{text: 'Delete file', variant: 'danger', role: 'option'}
]}
/>
```
Expand All @@ -60,6 +62,7 @@ import {ActionList} from '@primer/react/deprecated'

```jsx live deprecated
<ActionList
role="listbox"
groupMetadata={[
{groupId: '0'},
{groupId: '1', header: {title: 'Live query', variant: 'subtle'}},
Expand All @@ -68,34 +71,37 @@ import {ActionList} from '@primer/react/deprecated'
{groupId: '4'}
]}
items={[
{key: '1', leadingVisual: TypographyIcon, text: 'Rename', groupId: '0', trailingVisual: '⌘R'},
{key: '2', leadingVisual: VersionsIcon, text: 'Duplicate', groupId: '0'},
{key: '3', leadingVisual: SearchIcon, text: 'repo:github/github', groupId: '1'},
{key: '1', leadingVisual: TypographyIcon, text: 'Rename', groupId: '0', trailingVisual: '⌘R', role: 'option'},
{key: '2', leadingVisual: VersionsIcon, text: 'Duplicate', groupId: '0', role: 'option'},
{key: '3', leadingVisual: SearchIcon, text: 'repo:github/github', groupId: '1', role: 'option'},
{
key: '4',
leadingVisual: NoteIcon,
text: 'Table',
description: 'Information-dense table optimized for operations across teams',
descriptionVariant: 'block',
groupId: '2'
groupId: '2',
role: 'option'
},
{
key: '5',
leadingVisual: ProjectIcon,
text: 'Board',
description: 'Kanban-style board focused on visual states',
descriptionVariant: 'block',
groupId: '2'
groupId: '2',
role: 'option'
},
{
key: '6',
leadingVisual: FilterIcon,
text: 'Save sort and filters to current view',
disabled: true,
groupId: '3'
groupId: '3',
role: 'option'
},
{key: '7', leadingVisual: FilterIcon, text: 'Save sort and filters to new view', groupId: '3'},
{key: '8', leadingVisual: GearIcon, text: 'View settings', groupId: '4', trailingVisual: ArrowRightIcon}
{key: '7', leadingVisual: FilterIcon, text: 'Save sort and filters to new view', groupId: '3', role: 'option'},
{key: '8', leadingVisual: GearIcon, text: 'View settings', groupId: '4', trailingVisual: ArrowRightIcon, role: 'option'}
]}
/>
```
Expand All @@ -104,17 +110,21 @@ import {ActionList} from '@primer/react/deprecated'

```jsx deprecated
<ActionList
role="listbox"
items={[
{
text: 'Vanilla link',
role: 'option',
renderItem: props => <ActionList.Item as="a" href="/about" {...props} />
},
{
text: 'React Router link',
role: 'option',
renderItem: props => <ActionList.Item as={ReactRouterLikeLink} to="/about" {...props} />
},
{
text: 'NextJS style',
role: 'option',
renderItem: props => (
<NextJSLikeLink href="/about">
<ActionList.Item as="a" {...props} />
Expand Down
2 changes: 2 additions & 0 deletions src/Autocomplete/AutocompleteMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ function AutocompleteMenu<T extends AutocompleteItemProps>(props: AutocompleteMe
items.map(selectableItem => {
return {
...selectableItem,
_legacyEnterSupport: true, //TODO: Change behaviour, the enter key should not be used here.
role: 'option',
id: selectableItem.id,
selected: selectionVariant === 'multiple' ? selectedItemIds.includes(selectableItem.id) : undefined,
Expand Down Expand Up @@ -217,6 +218,7 @@ function AutocompleteMenu<T extends AutocompleteItemProps>(props: AutocompleteMe
? [
{
...addNewItem,
_legacyEnterSupport: true, //TODO: Change behaviour, the enter key should not be used here.
leadingVisual: () => <PlusIcon />,
onAction: (item: T) => {
// TODO: make it possible to pass a leadingVisual when using `addNewItem`
Expand Down
32 changes: 6 additions & 26 deletions src/FilteredActionList/FilteredActionList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import TextInput, {TextInputProps} from '../TextInput'
import Box from '../Box'
import {ActionList} from '../deprecated/ActionList'
import Spinner from '../Spinner'
import {useFocusZone} from '../hooks/useFocusZone'
import {useProvidedStateOrCreate} from '../hooks/useProvidedStateOrCreate'
import styled from 'styled-components'
import {get} from '../constants'
Expand All @@ -14,6 +13,7 @@ import useScrollFlash from '../hooks/useScrollFlash'
import {scrollIntoView} from '@primer/behaviors'
import type {ScrollIntoViewOptions} from '@primer/behaviors'
import {SxProp} from '../sx'
import VisuallyHidden from '../_VisuallyHidden'

const menuScrollMargins: ScrollIntoViewOptions = {startMargin: 0, endMargin: 8}

Expand All @@ -22,7 +22,7 @@ export interface FilteredActionListProps
ListPropsBase,
SxProp {
loading?: boolean
placeholderText: string
placeholderText?: string
filterValue?: string
onFilterChange: (value: string, e: React.ChangeEvent<HTMLInputElement>) => void
textInputProps?: Partial<Omit<TextInputProps, 'onChange'>>
Expand Down Expand Up @@ -56,10 +56,10 @@ export function FilteredActionList({
)

const scrollContainerRef = useRef<HTMLDivElement>(null)
const listContainerRef = useRef<HTMLDivElement>(null)
const inputRef = useProvidedRefOrCreate<HTMLInputElement>(providedInputRef)
const activeDescendantRef = useRef<HTMLElement>()
const listId = useSSRSafeId()
const inputDescriptionTextId = useSSRSafeId()
const onInputKeyPress: KeyboardEventHandler = useCallback(
event => {
if (event.key === 'Enter' && activeDescendantRef.current) {
Expand All @@ -74,28 +74,6 @@ export function FilteredActionList({
[activeDescendantRef]
)

useFocusZone(
{
containerRef: listContainerRef,
focusOutBehavior: 'wrap',
focusableElementFilter: element => {
return !(element instanceof HTMLInputElement)
},
activeDescendantFocus: inputRef,
onActiveDescendantChanged: (current, previous, directlyActivated) => {
activeDescendantRef.current = current

if (current && scrollContainerRef.current && directlyActivated) {
scrollIntoView(current, scrollContainerRef.current, menuScrollMargins)
}
}
},
[
// List ref isn't set while loading. Need to re-bind focus zone when it changes
loading
]
)

useEffect(() => {
// if items changed, we want to instantly move active descendant into view
if (activeDescendantRef.current && scrollContainerRef.current) {
Expand All @@ -119,16 +97,18 @@ export function FilteredActionList({
placeholder={placeholderText}
aria-label={placeholderText}
aria-controls={listId}
aria-describedby={inputDescriptionTextId}
{...textInputProps}
/>
<VisuallyHidden id={inputDescriptionTextId}>Items will be filtered as you type</VisuallyHidden>
</StyledHeader>
<Box ref={scrollContainerRef} overflow="auto">
{loading ? (
<Box width="100%" display="flex" flexDirection="row" justifyContent="center" pt={6} pb={7}>
<Spinner />
</Box>
) : (
<ActionList ref={listContainerRef} items={items} {...listProps} role="listbox" id={listId} />
<ActionList items={items} {...listProps} role="listbox" id={listId} />
)}
</Box>
</Box>
Expand Down
Loading