Skip to content

Commit 1d54fab

Browse files
authored
Fix combobox section filtering and Firefox gap issue (#4326)
1 parent 7fa0a88 commit 1d54fab

File tree

3 files changed

+53
-9
lines changed

3 files changed

+53
-9
lines changed

packages/@react-stately/combobox/src/useComboBoxState.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -364,10 +364,12 @@ function filterNodes<T>(collection: Collection<Node<T>>, nodes: Iterable<Node<T>
364364
for (let node of nodes) {
365365
if (node.type === 'section' && node.hasChildNodes) {
366366
let filtered = filterNodes(collection, getChildNodes(node, collection), inputValue, filter);
367-
if ([...filtered].length > 0) {
367+
if ([...filtered].some(node => node.type === 'item')) {
368368
filteredNode.push({...node, childNodes: filtered});
369369
}
370-
} else if (node.type !== 'section' && filter(node.textValue, inputValue)) {
370+
} else if (node.type === 'item' && filter(node.textValue, inputValue)) {
371+
filteredNode.push({...node});
372+
} else if (node.type !== 'item') {
371373
filteredNode.push({...node});
372374
}
373375
}

packages/react-aria-components/docs/GridList.mdx

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -735,8 +735,10 @@ function Example() {
735735
}
736736
}
737737

738-
.react-aria-DropIndicator[data-drop-target] {
739-
outline: 1px solid var(--highlight-background);
738+
.react-aria-DropIndicator {
739+
&[data-drop-target] {
740+
outline: 1px solid var(--highlight-background);
741+
}
740742

741743
@supports not selector(:has(.foo)) {
742744
/* Undo gap in browsers that don't support :has */
@@ -1022,8 +1024,10 @@ function Example() {
10221024
<summary style={{fontWeight: 'bold'}}><ChevronRight size="S" /> Show CSS</summary>
10231025

10241026
```css
1025-
.react-aria-DropIndicator[data-drop-target] {
1026-
outline: 1px solid var(--highlight-background);
1027+
.react-aria-DropIndicator {
1028+
&[data-drop-target] {
1029+
outline: 1px solid var(--highlight-background);
1030+
}
10271031

10281032
@supports not selector(:has(.foo)) {
10291033
/* Undo gap in browsers that don't support :has */
@@ -1095,8 +1099,10 @@ function Example() {
10951099
<summary style={{fontWeight: 'bold'}}><ChevronRight size="S" /> Show CSS</summary>
10961100

10971101
```css
1098-
.my-drop-indicator.active {
1099-
outline: 1px solid #e70073;
1102+
.my-drop-indicator {
1103+
&.active {
1104+
outline: 1px solid #e70073;
1105+
}
11001106

11011107
@supports not selector(:has(.foo)) {
11021108
/* Undo gap in browsers that don't support :has */

packages/react-aria-components/test/ComboBox.test.js

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
* governing permissions and limitations under the License.
1111
*/
1212

13-
import {Button, ComboBox, ComboBoxContext, Input, Item, Label, ListBox, Popover, Text} from '../';
13+
import {Button, ComboBox, ComboBoxContext, Header, Input, Item, Label, ListBox, Popover, Section, Text} from '../';
1414
import React from 'react';
1515
import {render, within} from '@react-spectrum/test-utils';
1616
import userEvent from '@testing-library/user-event';
@@ -84,4 +84,40 @@ describe('ComboBox', () => {
8484
userEvent.click(button);
8585
expect(button).toHaveAttribute('data-pressed');
8686
});
87+
88+
it('should support filtering sections', () => {
89+
let {getByRole} = render(
90+
<ComboBox>
91+
<Label>Preferred fruit or vegetable</Label>
92+
<Input />
93+
<Button />
94+
<Popover>
95+
<ListBox>
96+
<Section>
97+
<Header>Fruit</Header>
98+
<Item id="Apple">Apple</Item>
99+
<Item id="Banana">Banana</Item>
100+
</Section>
101+
<Section>
102+
<Header>Vegetable</Header>
103+
<Item id="Cabbage">Cabbage</Item>
104+
<Item id="Broccoli">Broccoli</Item>
105+
</Section>
106+
</ListBox>
107+
</Popover>
108+
</ComboBox>
109+
);
110+
111+
let input = getByRole('combobox');
112+
userEvent.type(input, 'p');
113+
114+
let listbox = getByRole('listbox');
115+
let groups = within(listbox).getAllByRole('group');
116+
expect(groups).toHaveLength(1);
117+
expect(groups[0]).toHaveAttribute('aria-labelledby');
118+
expect(document.getElementById(groups[0].getAttribute('aria-labelledby'))).toHaveTextContent('Fruit');
119+
120+
let options = within(groups[0]).getAllByRole('option');
121+
expect(options).toHaveLength(1);
122+
});
87123
});

0 commit comments

Comments
 (0)