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

[select] fix: ARIA listbox popup type and combobox list role #5348

Merged
merged 34 commits into from
Jun 6, 2022
Merged
Show file tree
Hide file tree
Changes from 28 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
9072606
fix list role
bvandercar-vt Jun 2, 2022
0b53086
allow for custom menuProps
bvandercar-vt Jun 2, 2022
4284050
add more props for combobox items
bvandercar-vt Jun 3, 2022
fe900ba
move aria props to entire tagInput
bvandercar-vt Jun 3, 2022
3f819f6
Merge branch 'develop' into bv/select-menu-role
bvandercar-vt Jun 3, 2022
079d996
remove
bvandercar-vt Jun 3, 2022
8e9f410
popoverKind
bvandercar-vt Jun 3, 2022
920734c
fix prop
bvandercar-vt Jun 3, 2022
ed6dd1b
use enum
bvandercar-vt Jun 3, 2022
797d807
fix import
bvandercar-vt Jun 3, 2022
53e0c88
fix imports
bvandercar-vt Jun 3, 2022
8585008
fix props
bvandercar-vt Jun 3, 2022
d586c6a
fix export impoty
bvandercar-vt Jun 3, 2022
89a45e2
Update packages/select/src/components/multi-select/multiSelect2.tsx
bvandercar-vt Jun 3, 2022
382770c
Update packages/select/src/components/multi-select/multiSelect2.tsx
bvandercar-vt Jun 3, 2022
05cf8ed
Update packages/select/src/components/select/select2.tsx
bvandercar-vt Jun 3, 2022
561875a
Update packages/select/src/components/multi-select/multiSelect2.tsx
bvandercar-vt Jun 3, 2022
3d087f2
Update packages/select/src/components/select/select2.tsx
bvandercar-vt Jun 3, 2022
e2f9556
Update packages/select/src/components/select/select2.tsx
bvandercar-vt Jun 3, 2022
599290a
Update packages/select/src/components/select/select2.tsx
bvandercar-vt Jun 3, 2022
7a8d66d
alph order props
bvandercar-vt Jun 3, 2022
f2b9585
listboxId
bvandercar-vt Jun 3, 2022
eeeb0b7
fix
bvandercar-vt Jun 3, 2022
0063836
fix
bvandercar-vt Jun 3, 2022
b4af6a2
fix type
bvandercar-vt Jun 3, 2022
7e6e5cc
fix
bvandercar-vt Jun 3, 2022
80ba2b1
style fix
bvandercar-vt Jun 3, 2022
3c9f8b2
style type
bvandercar-vt Jun 3, 2022
1aad667
fix id uinique
bvandercar-vt Jun 6, 2022
ed42f51
fix imort ts rule
bvandercar-vt Jun 6, 2022
2c82c96
fix import failure
bvandercar-vt Jun 6, 2022
0b58dda
fix import
bvandercar-vt Jun 6, 2022
f97ac9a
fix test
bvandercar-vt Jun 6, 2022
6de075e
fix remove unneede
bvandercar-vt Jun 6, 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
1 change: 1 addition & 0 deletions packages/popover2/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,6 @@ export {
StrictModifierNames,
} from "./popover2SharedProps";
export { IPopover2Props, Popover2Props, Popover2, Popover2InteractionKind } from "./popover2";
export { PopupKind } from "./popupKind";
export { ResizeSensor2, ResizeSensor2Props } from "./resizeSensor2";
export { ITooltip2Props, Tooltip2Props, Tooltip2 } from "./tooltip2";
35 changes: 31 additions & 4 deletions packages/select/src/components/multi-select/multiSelect2.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,20 +28,29 @@ import {
TagInputAddMethod,
TagInputProps,
} from "@blueprintjs/core";
import { Popover2 } from "@blueprintjs/popover2";
import { Popover2, PopupKind } from "@blueprintjs/popover2";

import { Classes, IListItemsProps, SelectPopoverProps } from "../../common";
import { IQueryListRendererProps, QueryList } from "../query-list/queryList";
import { IQueryListRendererProps, QueryList, QueryListProps } from "../query-list/queryList";

// N.B. selectedItems should really be a required prop, but is left optional for backwards compatibility

export interface MultiSelect2Props<T> extends IListItemsProps<T>, SelectPopoverProps {
export interface MultiSelect2Props<T>
extends IListItemsProps<T>,
Pick<QueryListProps<T>, "menuProps">,
adidahiya marked this conversation as resolved.
Show resolved Hide resolved
SelectPopoverProps {
/**
* Whether the component should take up the full width of its container.
* This overrides `popoverProps.fill` and `tagInputProps.fill`.
*/
fill?: boolean;

/**
* Adds `id={listboxId}` to the list Menu and `aria-controls={listboxId}` to the
* combobox element that opens it
*/
listboxId?: string;
adidahiya marked this conversation as resolved.
Show resolved Hide resolved

/**
* Callback invoked when an item is removed from the selection by
* removing its tag in the TagInput. This is generally more useful than
Expand Down Expand Up @@ -73,6 +82,11 @@ export interface MultiSelect2Props<T> extends IListItemsProps<T>, SelectPopoverP
*/
placeholder?: string;

/**
* Props to add to the `div` that wraps the TagInput
*/
popoverTargetProps?: React.HTMLAttributes<HTMLDivElement>;

/** Controlled selected values. */
selectedItems?: T[];

Expand Down Expand Up @@ -130,11 +144,17 @@ export class MultiSelect2<T> extends AbstractPureComponent2<MultiSelect2Props<T>

public render() {
// omit props specific to this component, spread the rest.
const { openOnKeyDown, popoverProps, tagInputProps, ...restProps } = this.props;
const { listboxId, openOnKeyDown, popoverProps, tagInputProps, ...restProps } = this.props;

const queryListMenuProps = {
id: listboxId,
...(restProps.menuProps ?? {}),
};

return (
<this.TypedQueryList
{...restProps}
menuProps={queryListMenuProps}
onItemSelect={this.handleItemSelect}
onQueryChange={this.handleQueryChange}
ref={this.refHandlers.queryList}
Expand All @@ -146,12 +166,14 @@ export class MultiSelect2<T> extends AbstractPureComponent2<MultiSelect2Props<T>
private renderQueryList = (listProps: IQueryListRendererProps<T>) => {
const {
fill,
listboxId,
tagInputProps = {},
popoverContentProps = {},
popoverProps = {},
popoverRef,
selectedItems = [],
placeholder,
popoverTargetProps = {},
} = this.props;
const { handlePaste, handleKeyDown, handleKeyUp } = listProps;

Expand Down Expand Up @@ -190,15 +212,20 @@ export class MultiSelect2<T> extends AbstractPureComponent2<MultiSelect2Props<T>
onInteraction={this.handlePopoverInteraction}
onOpened={this.handlePopoverOpened}
popoverClassName={classNames(Classes.MULTISELECT_POPOVER, popoverProps.popoverClassName)}
popupKind={PopupKind.LISTBOX}
ref={
popoverRef === undefined
? this.refHandlers.popover
: mergeRefs(this.refHandlers.popover, popoverRef)
}
>
<div
aria-controls={listboxId}
{...popoverTargetProps}
aria-expanded={this.state.isOpen}
onKeyDown={this.getTagInputKeyDownHandler(handleKeyDown)}
onKeyUp={this.getTagInputKeyUpHandler(handleKeyUp)}
role="combobox"
>
<TagInput
placeholder={placeholder}
Expand Down
9 changes: 7 additions & 2 deletions packages/select/src/components/query-list/queryList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ export interface IQueryListProps<T> extends IListItemsProps<T> {
*/
initialActiveItem?: T;

/**
* Additional props to apply to the `Menu` that is created within the `QueryList`
*/
menuProps?: React.HTMLAttributes<HTMLUListElement>;
adidahiya marked this conversation as resolved.
Show resolved Hide resolved

/**
* Callback invoked when user presses a key, after processing `QueryList`'s own key events
* (up/down to navigate active item). This callback is passed to `renderer` and (along with
Expand Down Expand Up @@ -343,7 +348,7 @@ export class QueryList<T> extends AbstractComponent2<QueryListProps<T>, IQueryLi

/** default `itemListRenderer` implementation */
private renderItemList = (listProps: IItemListRendererProps<T>) => {
const { initialContent, noResults } = this.props;
const { initialContent, noResults, menuProps } = this.props;

// omit noResults if createNewItemFromQuery and createNewItemRenderer are both supplied, and query is not empty
const createItemView = listProps.renderCreateItem();
Expand All @@ -354,7 +359,7 @@ export class QueryList<T> extends AbstractComponent2<QueryListProps<T>, IQueryLi
}
const createFirst = this.isCreateItemFirst();
return (
<Menu ulRef={listProps.itemsParentRef}>
<Menu role="listbox" {...menuProps} ulRef={listProps.itemsParentRef}>
{createFirst && createItemView}
{menuContent}
{!createFirst && createItemView}
Expand Down
32 changes: 28 additions & 4 deletions packages/select/src/components/select/select2.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,12 @@ import {
refHandler,
setRef,
} from "@blueprintjs/core";
import { Popover2 } from "@blueprintjs/popover2";
import { Popover2, PopupKind } from "@blueprintjs/popover2";

import { Classes, IListItemsProps, SelectPopoverProps } from "../../common";
import { IQueryListRendererProps, QueryList } from "../query-list/queryList";
import { IQueryListRendererProps, QueryList, QueryListProps } from "../query-list/queryList";

export interface Select2Props<T> extends IListItemsProps<T>, SelectPopoverProps {
export interface Select2Props<T> extends IListItemsProps<T>, Pick<QueryListProps<T>, "menuProps">, SelectPopoverProps {
children?: React.ReactNode;

/**
Expand Down Expand Up @@ -70,6 +70,17 @@ export interface Select2Props<T> extends IListItemsProps<T>, SelectPopoverProps
*/
inputProps?: InputGroupProps2;

/**
* Adds `id={listboxId}` to the list Menu and `aria-controls={listboxId}` to the
* combobox element that opens it
*/
listboxId?: string;

/**
* Props to add to the popover target wrapper element.
*/
popoverTargetProps?: React.HTMLAttributes<HTMLDivElement>;

/**
* Whether the active item should be reset to the first matching item _when
* the popover closes_. The query will also be reset to the empty string.
Expand Down Expand Up @@ -106,11 +117,17 @@ export class Select2<T> extends AbstractPureComponent2<Select2Props<T>, Select2S

public render() {
// omit props specific to this component, spread the rest.
const { filterable, inputProps, popoverProps, ...restProps } = this.props;
const { filterable, inputProps, listboxId, popoverProps, ...restProps } = this.props;

const queryListMenuProps = {
id: listboxId,
...(restProps.menuProps ?? {}),
};

return (
<this.TypedQueryList
{...restProps}
menuProps={queryListMenuProps}
onItemSelect={this.handleItemSelect}
ref={this.handleQueryListRef}
renderer={this.renderQueryList}
Expand All @@ -137,8 +154,10 @@ export class Select2<T> extends AbstractPureComponent2<Select2Props<T>, Select2S
filterable = true,
disabled = false,
inputProps = {},
listboxId,
popoverContentProps = {},
popoverProps = {},
popoverTargetProps = {},
popoverRef,
} = this.props;

Expand Down Expand Up @@ -179,11 +198,16 @@ export class Select2<T> extends AbstractPureComponent2<Select2Props<T>, Select2S
onOpened={this.handlePopoverOpened}
onOpening={this.handlePopoverOpening}
popoverClassName={classNames(Classes.SELECT_POPOVER, popoverProps.popoverClassName)}
popupKind={PopupKind.LISTBOX}
ref={popoverRef}
>
<div
aria-controls={listboxId}
{...popoverTargetProps}
aria-expanded={this.state.isOpen}
onKeyDown={this.state.isOpen ? handleKeyDown : this.handleTargetKeyDown}
onKeyUp={this.state.isOpen ? handleKeyUp : undefined}
role="combobox"
adidahiya marked this conversation as resolved.
Show resolved Hide resolved
>
{this.props.children}
</div>
Expand Down
36 changes: 31 additions & 5 deletions packages/select/src/components/suggest/suggest2.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,12 @@ import {
refHandler,
setRef,
} from "@blueprintjs/core";
import { Popover2 } from "@blueprintjs/popover2";
import { Popover2, PopupKind } from "@blueprintjs/popover2";

import { Classes, IListItemsProps, SelectPopoverProps } from "../../common";
import { IQueryListRendererProps, QueryList } from "../query-list/queryList";
import { IQueryListRendererProps, QueryList, QueryListProps } from "../query-list/queryList";

export interface Suggest2Props<T> extends IListItemsProps<T>, SelectPopoverProps {
export interface Suggest2Props<T> extends IListItemsProps<T>, Pick<QueryListProps<T>, "menuProps">, SelectPopoverProps {
/**
* Whether the popover should close after selecting an item.
*
Expand Down Expand Up @@ -68,6 +68,12 @@ export interface Suggest2Props<T> extends IListItemsProps<T>, SelectPopoverProps
*/
defaultSelectedItem?: T;

/**
* Adds `id={listboxId}` to the list Menu and `aria-controls={listboxId}` to the
* combobox element that opens it
*/
listboxId?: string;

/**
* The currently selected item, or `null` to indicate that no item is selected.
* If omitted or `undefined`, this prop will be uncontrolled (managed by the component's state).
Expand Down Expand Up @@ -131,10 +137,17 @@ export class Suggest2<T> extends AbstractPureComponent2<Suggest2Props<T>, Sugges

public render() {
// omit props specific to this component, spread the rest.
const { disabled, inputProps, popoverProps, ...restProps } = this.props;
const { disabled, inputProps, listboxId, popoverProps, ...restProps } = this.props;

const queryListMenuProps = {
id: listboxId,
...(restProps.menuProps ?? {}),
};

return (
<this.TypedQueryList
{...restProps}
menuProps={queryListMenuProps}
initialActiveItem={this.props.selectedItem ?? undefined}
onItemSelect={this.handleItemSelect}
ref={this.handleQueryListRef}
Expand Down Expand Up @@ -169,7 +182,14 @@ export class Suggest2<T> extends AbstractPureComponent2<Suggest2Props<T>, Sugges
}

private renderQueryList = (listProps: IQueryListRendererProps<T>) => {
const { fill, inputProps = {}, popoverContentProps = {}, popoverProps = {}, popoverRef } = this.props;
const {
fill,
inputProps = {},
listboxId,
popoverContentProps = {},
popoverProps = {},
popoverRef,
} = this.props;
const { isOpen, selectedItem } = this.state;
const { handleKeyDown, handleKeyUp } = listProps;
const { autoComplete = "off", placeholder = "Search..." } = inputProps;
Expand Down Expand Up @@ -206,18 +226,24 @@ export class Suggest2<T> extends AbstractPureComponent2<Suggest2Props<T>, Sugges
onOpened={this.handlePopoverOpened}
onOpening={this.handlePopoverOpening}
popoverClassName={classNames(Classes.SELECT_POPOVER, popoverProps.popoverClassName)}
popupKind={PopupKind.LISTBOX}
ref={popoverRef}
>
<InputGroup
autoComplete={autoComplete}
disabled={this.props.disabled}
aria-controls={listboxId}
{...inputProps}
aria-autocomplete="list"
aria-expanded={this.state.isOpen}
inputRef={this.handleInputRef}
onChange={listProps.handleQueryChange}
onFocus={this.handleInputFocus}
onKeyDown={this.getTargetKeyDownHandler(handleKeyDown)}
onKeyUp={this.getTargetKeyUpHandler(handleKeyUp)}
placeholder={inputPlaceholder}
role="combobox"
type="text"
value={inputValue}
/>
</Popover2>
Expand Down