Skip to content

Commit a8903d3

Browse files
authored
Stop dialog inside collection from closing due to typeahead (#4328)
* Stop dialog inside collection from closing due to typeahead
1 parent 42c65e6 commit a8903d3

File tree

3 files changed

+90
-2
lines changed

3 files changed

+90
-2
lines changed

packages/@react-aria/selection/src/useTypeSelect.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ export function useTypeSelect(options: AriaTypeSelectOptions): TypeSelectAria {
5353

5454
let onKeyDown = (e: KeyboardEvent) => {
5555
let character = getStringForKey(e.key);
56-
if (!character || e.ctrlKey || e.metaKey) {
56+
if (!character || e.ctrlKey || e.metaKey || !e.currentTarget.contains(e.target as HTMLElement)) {
5757
return;
5858
}
5959

packages/@react-spectrum/table/stories/Table.stories.tsx

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1791,3 +1791,53 @@ export const ResizingControlledHideHeader: TableStory = {
17911791
`}}
17921792
};
17931793

1794+
let typeAheadColumns = [
1795+
{name: 'First Name', id: 'firstname', isRowHeader: true},
1796+
{name: 'Last Name', id: 'lastname', isRowHeader: true},
1797+
{name: 'Birthday', id: 'birthday'},
1798+
{name: 'Edit', id: 'edit'}
1799+
];
1800+
let typeAheadRows = [
1801+
...Array.from({length: 100}, (v, i) => ({id: i, firstname: 'Aubrey', lastname: 'Sheppard', birthday: 'May 7'})),
1802+
{id: 101, firstname: 'John', lastname: 'Doe', birthday: 'May 7'}
1803+
];
1804+
export const TypeaheadWithDialog: TableStory = {
1805+
render: (args) => (
1806+
<div style={{height: '90vh'}}>
1807+
<TableView aria-label="Table" selectionMode="none" height="100%" {...args}>
1808+
<TableHeader columns={typeAheadColumns}>
1809+
{(col) => (
1810+
<Column key={col.id} isRowHeader={col.isRowHeader}>{col.name}</Column>
1811+
)}
1812+
</TableHeader>
1813+
<TableBody items={typeAheadRows}>
1814+
{(item) => (
1815+
<Row key={item.id}>
1816+
{(key) =>
1817+
key === 'edit' ? (
1818+
<Cell>
1819+
<DialogTrigger>
1820+
<ActionButton aria-label="Add Info">
1821+
<Add />
1822+
</ActionButton>
1823+
<Dialog>
1824+
<Heading>Add Info</Heading>
1825+
<Divider />
1826+
<Content>
1827+
<TextField label="Enter a J" />
1828+
</Content>
1829+
</Dialog>
1830+
</DialogTrigger>
1831+
</Cell>
1832+
) : (
1833+
<Cell>{item[key]}</Cell>
1834+
)
1835+
}
1836+
</Row>
1837+
)}
1838+
</TableBody>
1839+
</TableView>
1840+
</div>
1841+
)
1842+
};
1843+

packages/@react-spectrum/table/test/Table.test.js

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ import userEvent from '@testing-library/user-event';
3636
let {
3737
InlineDeleteButtons: DeletableRowsTable,
3838
EmptyStateStory: EmptyStateTable,
39-
WithBreadcrumbNavigation: TableWithBreadcrumbs
39+
WithBreadcrumbNavigation: TableWithBreadcrumbs,
40+
TypeaheadWithDialog: TypeaheadWithDialog
4041
} = composeStories(stories);
4142

4243

@@ -1412,6 +1413,43 @@ describe('TableView', function () {
14121413
moveFocus('S');
14131414
expect(document.activeElement).toBe(getCell(tree, 'Sam'));
14141415
});
1416+
1417+
describe('type ahead with dialog triggers', function () {
1418+
beforeEach(function () {
1419+
offsetHeight.mockRestore();
1420+
offsetHeight = jest.spyOn(window.HTMLElement.prototype, 'clientHeight', 'get')
1421+
.mockImplementationOnce(() => 20)
1422+
.mockImplementation(() => 100);
1423+
});
1424+
afterEach(function () {
1425+
offsetHeight.mockRestore();
1426+
offsetHeight = jest.spyOn(window.HTMLElement.prototype, 'clientHeight', 'get').mockImplementation(() => 1000);
1427+
});
1428+
it('does not pick up typeahead from a dialog', function () {
1429+
offsetHeight = jest.spyOn(window.HTMLElement.prototype, 'clientHeight', 'get')
1430+
.mockImplementationOnce(() => 20)
1431+
.mockImplementation(() => 100);
1432+
let tree = render(<TypeaheadWithDialog />);
1433+
let trigger = tree.getAllByRole('button')[0];
1434+
triggerPress(trigger);
1435+
act(() => {
1436+
jest.runAllTimers();
1437+
});
1438+
let textfield = tree.getByLabelText('Enter a J');
1439+
act(() => {textfield.focus();});
1440+
fireEvent.keyDown(textfield, {key: 'J'});
1441+
fireEvent.keyUp(textfield, {key: 'J'});
1442+
act(() => {
1443+
jest.runAllTimers();
1444+
});
1445+
expect(document.activeElement).toBe(textfield);
1446+
fireEvent.keyDown(document.activeElement, {key: 'Escape'});
1447+
fireEvent.keyUp(document.activeElement, {key: 'Escape'});
1448+
act(() => {
1449+
jest.runAllTimers();
1450+
});
1451+
});
1452+
});
14151453
});
14161454

14171455
describe('focus marshalling', function () {

0 commit comments

Comments
 (0)