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

Close select on escape key #645

Merged
merged 6 commits into from
Feb 20, 2024
Merged
Changes from 4 commits
Commits
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
189 changes: 167 additions & 22 deletions stories/components/select.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
MenuItem,
} from '@blueprintjs/core';
import { ItemListRenderer, ItemRenderer, Select } from '@blueprintjs/select';
import { Fragment, useState } from 'react';
import { Dispatch, Fragment, SetStateAction, useState } from 'react';

import { Button, useOnOff } from '../../src/components';

Expand Down Expand Up @@ -82,26 +82,58 @@ const renderMenu: ItemListRenderer<ItemsType> = ({
</Menu>
);
};
const renderMenuNested: ItemListRenderer<ItemsType> = ({
items,
itemsParentRef,
renderItem,
menuProps,
}) => {
const { groups, withoutGroup } = getGroups(items);

return (
<Menu role="listbox" {...menuProps} ulRef={itemsParentRef}>
{groups.map(({ group, items }) => (
<MenuItem key={group} text={group}>
{items.map(renderItem)}
</MenuItem>
))}
{groups.length > 0 && withoutGroup.length > 0 && <MenuDivider />}
{withoutGroup.map(renderItem)}
</Menu>
);
};
function renderMenuNested(
value: ItemsType | null,
[hoveredGroup, setHoveredGroup]: [
string | undefined,
Dispatch<SetStateAction<string | undefined>>,
],
) {
const render: ItemListRenderer<ItemsType> = ({
items,
itemsParentRef,
renderItem,
menuProps,
activeItem,
}) => {
const { groups, withoutGroup } = getGroups(items);
return (
<Menu role="listbox" {...menuProps} ulRef={itemsParentRef}>
{groups.map(({ group, items }) => (
<MenuItem
key={group}
text={group}
active={items.map((item) => item === activeItem).includes(true)}
selected={items
.map((item) => item.label === value?.label)
.includes(true)}
popoverProps={{
isOpen: hoveredGroup
? hoveredGroup === group
: items.map((item) => item === activeItem).includes(true),
onInteraction: (nextOpenState) => {
if (items.map((item) => item === activeItem).includes(true)) {
return;
}
if (nextOpenState) {
setHoveredGroup(group);
} else if (hoveredGroup) {
setHoveredGroup(undefined);
}
},
}}
roleStructure="listoption"
>
{items.map(renderItem)}
</MenuItem>
))}
{groups.length > 0 && withoutGroup.length > 0 && <MenuDivider />}
{withoutGroup.map(renderItem)}
</Menu>
);
};
return render;
}

export function OnlyOptions() {
const [value, setValue] = useState<ItemsType | null>(null);
Expand All @@ -114,6 +146,15 @@ export function OnlyOptions() {
filterable={false}
itemsEqual="label"
popoverTargetProps={{ style: { display: 'inline-block' } }}
popoverProps={{
wadjih-bencheikh18 marked this conversation as resolved.
Show resolved Hide resolved
onOpened: (node) => {
const firstUl = node.querySelector('ul');
if (firstUl) {
firstUl.tabIndex = 0;
firstUl.focus();
}
},
}}
>
<Button
text={value?.label ?? 'Select a status'}
Expand Down Expand Up @@ -143,6 +184,15 @@ export function OnlyCategories() {
{ label: 'Tomato', group: 'Vegetables' },
]}
popoverTargetProps={{ style: { display: 'inline-block' } }}
popoverProps={{
onOpened: (node) => {
const firstUl = node.querySelector('ul');
if (firstUl) {
firstUl.tabIndex = 0;
firstUl.focus();
}
},
}}
>
<Button
text={value?.label ?? 'Select'}
Expand Down Expand Up @@ -175,6 +225,15 @@ export function OptionsWithCategories() {
{ label: 'Beef' },
]}
popoverTargetProps={{ style: { display: 'inline-block' } }}
popoverProps={{
onOpened: (node) => {
const firstUl = node.querySelector('ul');
if (firstUl) {
firstUl.tabIndex = 0;
firstUl.focus();
}
},
}}
>
<Button
text={value?.label ?? 'Select'}
Expand All @@ -187,14 +246,15 @@ export function OptionsWithCategories() {
}
export function CategoriesNested() {
const [value, setValue] = useState<ItemsType | null>(null);
const hoverState = useState<string | undefined>(undefined);
return (
<>
<Select
onItemSelect={(item) => setValue(item)}
itemRenderer={getItemRenderer(value)}
filterable={false}
itemsEqual="label"
itemListRenderer={renderMenuNested}
itemListRenderer={renderMenuNested(value, hoverState)}
items={[
{ label: 'Apple', group: 'Fruits' },
{ label: 'Banana', group: 'Fruits' },
Expand All @@ -206,6 +266,15 @@ export function CategoriesNested() {
{ label: 'Beef' },
]}
popoverTargetProps={{ style: { display: 'inline-block' } }}
popoverProps={{
onOpened: (node) => {
const firstUl = node.querySelector('ul');
if (firstUl) {
firstUl.tabIndex = 0;
firstUl.focus();
}
},
}}
>
<Button
text={value?.label ?? 'Select'}
Expand All @@ -229,6 +298,15 @@ export function DisabledOptions() {
filterable={false}
itemsEqual="label"
popoverTargetProps={{ style: { display: 'inline-block' } }}
popoverProps={{
onOpened: (node) => {
const firstUl = node.querySelector('ul');
if (firstUl) {
firstUl.tabIndex = 0;
firstUl.focus();
}
},
}}
>
<Button
text={value?.label ?? 'Select a status'}
Expand Down Expand Up @@ -261,6 +339,16 @@ export function DisabledInCategories() {
itemDisabled={(item) =>
item.label === 'Potato' || item.group === 'Fruits'
}
popoverTargetProps={{ style: { display: 'inline-block' } }}
popoverProps={{
onOpened: (node) => {
const firstUl = node.querySelector('ul');
if (firstUl) {
firstUl.tabIndex = 0;
firstUl.focus();
}
},
}}
>
<Button
text={value?.label ?? 'Select'}
Expand All @@ -283,6 +371,16 @@ export function Disabled() {
filterable={false}
itemsEqual="label"
disabled
popoverProps={{
onOpened: (node) => {
const firstUl = node.querySelector('ul');
if (firstUl) {
firstUl.tabIndex = 0;
firstUl.focus();
}
},
}}
popoverTargetProps={{ style: { display: 'inline-block' } }}
>
<Button
disabled
Expand All @@ -304,7 +402,17 @@ export function WithCustomStyle() {
onItemSelect={setValue}
filterable={false}
itemsEqual="label"
popoverTargetProps={{ style: { display: 'inline-block' } }}
popoverContentProps={{ style: { width: '500px' } }}
popoverProps={{
onOpened: (node) => {
const firstUl = node.querySelector('ul');
if (firstUl) {
firstUl.tabIndex = 0;
firstUl.focus();
}
},
}}
>
<Button
style={{ width: '500px' }}
Expand All @@ -327,6 +435,16 @@ export function FixedValueNoopHandle() {
itemRenderer={getItemRenderer(value)}
filterable={false}
itemsEqual="label"
popoverTargetProps={{ style: { display: 'inline-block' } }}
popoverProps={{
onOpened: (node) => {
const firstUl = node.querySelector('ul');
if (firstUl) {
firstUl.tabIndex = 0;
firstUl.focus();
}
},
}}
>
<Button
text={value.label ?? 'Select a status'}
Expand All @@ -348,6 +466,16 @@ export function nullValueNoopHandle() {
itemRenderer={getItemRenderer(value)}
filterable={false}
itemsEqual="label"
popoverTargetProps={{ style: { display: 'inline-block' } }}
popoverProps={{
onOpened: (node) => {
const firstUl = node.querySelector('ul');
if (firstUl) {
firstUl.tabIndex = 0;
firstUl.focus();
}
},
}}
>
<Button
text={value ?? 'Select a status'}
Expand All @@ -369,6 +497,16 @@ export function ResetButton() {
itemRenderer={getItemRenderer(value)}
filterable={false}
itemsEqual="label"
popoverTargetProps={{ style: { display: 'inline-block' } }}
popoverProps={{
onOpened: (node) => {
const firstUl = node.querySelector('ul');
if (firstUl) {
firstUl.tabIndex = 0;
firstUl.focus();
}
},
}}
>
<Button
text={value?.label ?? 'Select a status'}
Expand Down Expand Up @@ -409,6 +547,13 @@ export function InDialog() {
itemsEqual="label"
popoverProps={{
positioningStrategy: 'fixed',
onOpened: (node) => {
const firstLi = node.querySelector('li');
if (firstLi) {
firstLi.tabIndex = 0;
firstLi.focus();
}
},
}}
popoverTargetProps={{
style: { display: 'inline-block' },
Expand Down
Loading