Skip to content

Commit f9aea93

Browse files
committed
initial progress for making Tree loadmore spinner keyboard focusable
see comments for bugs noted
1 parent 0ef52ef commit f9aea93

File tree

4 files changed

+34
-21
lines changed

4 files changed

+34
-21
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: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ html {
1313
overflow: auto;
1414
}
1515

16-
.tree-item {
16+
.tree-item,
17+
.tree-loader {
1718
padding: 4px 5px;
1819
outline: none;
1920
cursor: default;

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

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -463,7 +463,7 @@ export const TreeItem = /*#__PURE__*/ createBranchComponent('item', <T extends o
463463
);
464464
});
465465

466-
export interface UNSTABLE_TreeLoadingIndicatorRenderProps {
466+
export interface UNSTABLE_TreeLoadingIndicatorRenderProps extends Pick<TreeItemRenderProps, 'isFocused' | 'isFocusVisible'> {
467467
/**
468468
* What level the tree item has within the tree.
469469
* @selector [data-level]
@@ -474,41 +474,47 @@ export interface UNSTABLE_TreeLoadingIndicatorRenderProps {
474474
export interface TreeLoaderProps extends RenderProps<UNSTABLE_TreeLoadingIndicatorRenderProps>, StyleRenderProps<UNSTABLE_TreeLoadingIndicatorRenderProps> {}
475475

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

482+
// TODO: now that we are making the loading indicators focusable, guess we need to add all the styling props
483+
// Prob just want Focus and focusVisible, maybe hover?
483484
let ariaProps = {
485+
role: 'row',
484486
'aria-level': rowProps['aria-level'],
485487
'aria-posinset': rowProps['aria-posinset'],
486-
'aria-setsize': rowProps['aria-setsize']
488+
'aria-setsize': rowProps['aria-setsize'],
489+
tabIndex: rowProps.tabIndex
487490
};
488491

492+
let {isFocusVisible, focusProps} = useFocusRing();
493+
489494
let renderProps = useRenderProps({
490495
...props,
491496
id: undefined,
492497
children: item.rendered,
493498
defaultClassName: 'react-aria-TreeLoader',
494499
values: {
495-
level
500+
level,
501+
isFocused: states.isFocused,
502+
isFocusVisible
496503
}
497504
});
498505

499506
return (
500-
<>
501-
<div
502-
role="row"
503-
ref={ref}
504-
{...mergeProps(filterDOMProps(props as any), ariaProps)}
505-
{...renderProps}
506-
data-level={level}>
507-
<div role="gridcell" aria-colindex={1}>
508-
{renderProps.children}
509-
</div>
507+
<div
508+
ref={ref}
509+
{...mergeProps(filterDOMProps(props as any), ariaProps, focusProps)}
510+
{...renderProps}
511+
data-focused={states.isFocused || undefined}
512+
data-focus-visible={isFocusVisible || undefined}
513+
data-level={level}>
514+
<div {...gridCellProps}>
515+
{renderProps.children}
510516
</div>
511-
</>
517+
</div>
512518
);
513519
});
514520

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

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

203203
const MyTreeLoader = () => {
204204
return (
205-
<UNSTABLE_TreeLoadingIndicator>
205+
<UNSTABLE_TreeLoadingIndicator
206+
className={({isFocused, isFocusVisible}) => classNames(styles, 'tree-loader', {
207+
focused: isFocused,
208+
'focus-visible': isFocusVisible
209+
})}>
206210
{({level}) => {
207211
let message = `Level ${level} loading spinner`;
208212
if (level === 1) {
@@ -402,6 +406,8 @@ function LoadingStoryDepOnTop(args: TreeProps<unknown> & {isLoading: boolean}) {
402406
);
403407
}
404408

409+
// TODO: this story isn't quite working with PageUp/Down. Loading spinner gets focused but then you can't use PageUp/Down anymore
410+
// Also ArrowDown doesn't bring the spinner into view
405411
export const LoadingStoryDepOnTopStory = {
406412
render: LoadingStoryDepOnTop,
407413
args: {

0 commit comments

Comments
 (0)