Skip to content

Commit

Permalink
feat(RAC Breadcrumbs): add autoFocusCurrent to RAC Breadcrumbs (#6325)
Browse files Browse the repository at this point in the history
  • Loading branch information
reidbarber authored May 3, 2024
1 parent 800f9a0 commit 122d0c8
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 12 deletions.
32 changes: 20 additions & 12 deletions packages/react-aria-components/src/Breadcrumbs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ export interface BreadcrumbsProps<T> extends Omit<CollectionProps<T>, 'disabledK
/** Whether the breadcrumbs are disabled. */
isDisabled?: boolean,
/** Handler that is called when a breadcrumb is clicked. */
onAction?: (key: Key) => void
onAction?: (key: Key) => void,
/** Whether to autoFocus the last Breadcrumb item when the Breadcrumbs render. */
autoFocusCurrent?: boolean
}

export const BreadcrumbsContext = createContext<ContextValue<BreadcrumbsProps<any>, HTMLOListElement>>(null);
Expand Down Expand Up @@ -54,14 +56,18 @@ function BreadcrumbsInner<T extends object>({props, collection, breadcrumbsRef:
slot={props.slot || undefined}
style={props.style}
className={props.className ?? 'react-aria-Breadcrumbs'}>
{[...collection].map((node, i) => (
<BreadcrumbItem
key={node.key}
node={node}
isCurrent={i === collection.size - 1}
isDisabled={props.isDisabled}
onAction={props.onAction} />
))}
{[...collection].map((node, i) => {
let isCurrent = i === collection.size - 1;
return (
<BreadcrumbItem
key={node.key}
node={node}
isCurrent={isCurrent}
isDisabled={props.isDisabled}
onAction={props.onAction}
autoFocus={props.autoFocusCurrent && isCurrent} />
);
})}
</ol>
);
}
Expand Down Expand Up @@ -93,15 +99,17 @@ interface BreadcrumbItemProps {
node: Node<object>,
isCurrent: boolean,
isDisabled?: boolean,
onAction?: (key: Key) => void
onAction?: (key: Key) => void,
autoFocus?: boolean
}

function BreadcrumbItem({node, isCurrent, isDisabled, onAction}: BreadcrumbItemProps) {
function BreadcrumbItem({node, isCurrent, isDisabled, onAction, autoFocus}: BreadcrumbItemProps) {
// Recreating useBreadcrumbItem because we want to use composition instead of having the link builtin.
let linkProps = {
'aria-current': isCurrent ? 'page' : null,
isDisabled: isDisabled || isCurrent,
onPress: () => onAction?.(node.key)
onPress: () => onAction?.(node.key),
autoFocus: autoFocus
};

return (
Expand Down
38 changes: 38 additions & 0 deletions packages/react-aria-components/stories/Breadcrumbs.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright 2022 Adobe. All rights reserved.
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
* OF ANY KIND, either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/

import {Breadcrumb, Breadcrumbs, Link} from 'react-aria-components';
import React from 'react';

export default {
title: 'React Aria Components',
component: Breadcrumbs,
argTypes: {
autoFocusCurrent: {
control: {type: 'boolean'}
}
}
};

export const BreadcrumbsExample = (args: any) => (
<Breadcrumbs {...args}>
<Breadcrumb>
<Link href="/">Home</Link>
</Breadcrumb>
<Breadcrumb>
<Link href="/react-aria">React Aria</Link>
</Breadcrumb>
<Breadcrumb>
<Link href="/react-aria">Breadcrumbs</Link>
</Breadcrumb>
</Breadcrumbs>
);
13 changes: 13 additions & 0 deletions packages/react-aria-components/test/Breadcrumbs.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,4 +103,17 @@ describe('Breadcrumbs', () => {
let item = getByRole('listitem');
expect(breadcrumbRef.current).toBe(item);
});

it('should support autoFocusCurrent', () => {
let {getAllByRole} = render(
<Breadcrumbs autoFocusCurrent>
<Breadcrumb><Link href="/">Home</Link></Breadcrumb>
<Breadcrumb><Link href="/react-aria">React Aria</Link></Breadcrumb>
<Breadcrumb><Link href="/react-aria">useBreadcrumbs</Link></Breadcrumb>
</Breadcrumbs>
);

let links = getAllByRole('link');
expect(links[2]).toHaveFocus();
});
});

1 comment on commit 122d0c8

@rspbot
Copy link

@rspbot rspbot commented on 122d0c8 May 3, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.