Skip to content

Commit ea7f3e6

Browse files
authored
Revert "Revert "feat: focus loading indicator in rac tree (#8270)" (#8336)" (#8351)
This reverts commit 2aa1851.
1 parent cf743b9 commit ea7f3e6

File tree

5 files changed

+37
-25
lines changed

5 files changed

+37
-25
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ export class ListKeyboardDelegate<T> implements KeyboardDelegate {
7878
let nextKey = key;
7979
while (nextKey != null) {
8080
let item = this.collection.getItem(nextKey);
81-
if (item?.type === 'item' && !this.isDisabled(item)) {
81+
if (item?.type === 'loader' || (item?.type === 'item' && !this.isDisabled(item))) {
8282
return nextKey;
8383
}
8484

packages/react-aria-components/example/index.css

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ html {
2727
}
2828
}
2929

30+
.tree-loader,
3031
.tree-item {
3132
padding: 4px 5px;
3233
outline: none;

packages/react-aria-components/src/Tree.tsx

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -695,7 +695,7 @@ export const TreeItem = /*#__PURE__*/ createBranchComponent('item', <T extends o
695695
);
696696
});
697697

698-
export interface UNSTABLE_TreeLoadingIndicatorRenderProps {
698+
export interface UNSTABLE_TreeLoadingIndicatorRenderProps extends Pick<TreeItemRenderProps, 'isFocused' | 'isFocusVisible'> {
699699
/**
700700
* What level the tree item has within the tree.
701701
* @selector [data-level]
@@ -707,36 +707,44 @@ export interface TreeLoaderProps extends RenderProps<UNSTABLE_TreeLoadingIndicat
707707

708708
export const UNSTABLE_TreeLoadingIndicator = createLeafComponent('loader', function TreeLoader<T extends object>(props: TreeLoaderProps, ref: ForwardedRef<HTMLDivElement>, item: Node<T>) {
709709
let state = useContext(TreeStateContext)!;
710-
// This loader row is is non-interactable, but we want the same aria props calculated as a typical row
711-
// @ts-ignore
712-
let {rowProps} = useTreeItem({node: item}, state, ref);
710+
ref = useObjectRef<HTMLDivElement>(ref);
711+
let {rowProps, gridCellProps, ...states} = useTreeItem({node: item}, state, ref);
713712
let level = rowProps['aria-level'] || 1;
714713

715714
let ariaProps = {
715+
role: 'row',
716716
'aria-level': rowProps['aria-level'],
717717
'aria-posinset': rowProps['aria-posinset'],
718-
'aria-setsize': rowProps['aria-setsize']
718+
'aria-setsize': rowProps['aria-setsize'],
719+
tabIndex: rowProps.tabIndex
719720
};
720721

722+
let {isFocusVisible, focusProps} = useFocusRing();
723+
721724
let renderProps = useRenderProps({
722725
...props,
723726
id: undefined,
724727
children: item.rendered,
725728
defaultClassName: 'react-aria-TreeLoader',
726729
values: {
727-
level
730+
level,
731+
isFocused: states.isFocused,
732+
isFocusVisible
728733
}
729734
});
730735

731736
return (
732737
<>
733738
<div
734-
role="row"
735739
ref={ref}
736-
{...mergeProps(filterDOMProps(props as any), ariaProps)}
740+
{...mergeProps(filterDOMProps(props as any), ariaProps, focusProps)}
737741
{...renderProps}
742+
data-key={rowProps['data-key']}
743+
data-collection={rowProps['data-collection']}
744+
data-focused={states.isFocused || undefined}
745+
data-focus-visible={isFocusVisible || undefined}
738746
data-level={level}>
739-
<div role="gridcell" aria-colindex={1}>
747+
<div {...gridCellProps}>
740748
{renderProps.children}
741749
</div>
742750
</div>

packages/react-aria-components/stories/Tree.stories.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,11 @@ let rows = [
322322

323323
const MyTreeLoader = () => {
324324
return (
325-
<UNSTABLE_TreeLoadingIndicator>
325+
<UNSTABLE_TreeLoadingIndicator
326+
className={({isFocused, isFocusVisible}) => classNames(styles, 'tree-loader', {
327+
focused: isFocused,
328+
'focus-visible': isFocusVisible
329+
})}>
326330
{({level}) => {
327331
let message = `Level ${level} loading spinner`;
328332
if (level === 1) {

packages/react-aria-components/test/Tree.test.tsx

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1149,7 +1149,7 @@ describe('Tree', () => {
11491149
expect(cell).toHaveAttribute('aria-colindex', '1');
11501150
});
11511151

1152-
it('should not focus the load more row when using ArrowDown/ArrowUp', async () => {
1152+
it('should focus the load more row when using ArrowDown/ArrowUp', async () => {
11531153
let {getAllByRole} = render(<LoadingMoreTree isLoading />);
11541154

11551155
let rows = getAllByRole('row');
@@ -1158,19 +1158,18 @@ describe('Tree', () => {
11581158

11591159
await user.tab();
11601160
expect(document.activeElement).toBe(rows[0]);
1161-
for (let i = 0; i < 5; i++) {
1161+
for (let i = 1; i < 8; i++) {
11621162
await user.keyboard('{ArrowDown}');
1163+
expect(document.activeElement).toBe(rows[i]);
11631164
}
1164-
expect(document.activeElement).toBe(rows[5]);
11651165

1166-
await user.keyboard('{ArrowDown}');
1167-
expect(document.activeElement).toBe(rows[7]);
1168-
1169-
await user.keyboard('{ArrowUp}');
1170-
expect(document.activeElement).toBe(rows[5]);
1166+
for (let i = 6; i >= 0; i--) {
1167+
await user.keyboard('{ArrowUp}');
1168+
expect(document.activeElement).toBe(rows[i]);
1169+
}
11711170
});
11721171

1173-
it('should not focus the load more row when using End', async () => {
1172+
it('should focus the load more row when using End', async () => {
11741173
let {getAllByRole} = render(<LoadingMoreTree isLoading />);
11751174

11761175
let rows = getAllByRole('row');
@@ -1180,14 +1179,14 @@ describe('Tree', () => {
11801179
await user.tab();
11811180
expect(document.activeElement).toBe(rows[0]);
11821181
await user.keyboard('{End}');
1183-
expect(document.activeElement).toBe(rows[20]);
1182+
expect(document.activeElement).toBe(rows[21]);
11841183

11851184
// Check that it didn't shift the focusedkey to the loader key even if DOM focus didn't shift to the loader
11861185
await user.keyboard('{ArrowUp}');
1187-
expect(document.activeElement).toBe(rows[19]);
1186+
expect(document.activeElement).toBe(rows[20]);
11881187
});
11891188

1190-
it('should not focus the load more row when using PageDown', async () => {
1189+
it('should focus the load more row when using PageDown', async () => {
11911190
let {getAllByRole} = render(<LoadingMoreTree isLoading />);
11921191

11931192
let rows = getAllByRole('row');
@@ -1197,11 +1196,11 @@ describe('Tree', () => {
11971196
await user.tab();
11981197
expect(document.activeElement).toBe(rows[0]);
11991198
await user.keyboard('{PageDown}');
1200-
expect(document.activeElement).toBe(rows[20]);
1199+
expect(document.activeElement).toBe(rows[21]);
12011200

12021201
// Check that it didn't shift the focusedkey to the loader key even if DOM focus didn't shift to the loader
12031202
await user.keyboard('{ArrowUp}');
1204-
expect(document.activeElement).toBe(rows[19]);
1203+
expect(document.activeElement).toBe(rows[20]);
12051204
});
12061205

12071206
it('should not render no results state and the loader at the same time', () => {

0 commit comments

Comments
 (0)