Skip to content

Commit

Permalink
Add docs for links in collections and client side routing guide (#5078)
Browse files Browse the repository at this point in the history
  • Loading branch information
devongovett authored Sep 20, 2023
1 parent a399db1 commit 15721e5
Show file tree
Hide file tree
Showing 74 changed files with 1,710 additions and 279 deletions.
1 change: 1 addition & 0 deletions packages/@adobe/react-spectrum/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"dependencies": {
"@react-aria/i18n": "^3.8.2",
"@react-aria/ssr": "^3.8.0",
"@react-aria/utils": "^3.20.0",
"@react-aria/visually-hidden": "^3.8.4",
"@react-spectrum/actionbar": "^3.2.0",
"@react-spectrum/actiongroup": "^3.9.2",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,7 @@ governing permissions and limitations under the License.
margin-block-end: 0;
font-size: inherit;

&[href],
&[tabindex="0"] {
&:not([aria-disabled]) {
cursor: pointer;

&:hover,
Expand Down
4 changes: 4 additions & 0 deletions packages/@adobe/spectrum-css-temp/components/table/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,10 @@ svg.spectrum-Table-sortedIcon {
cursor: default;
transition: background-color var(--spectrum-global-animation-duration-100) ease-in-out;

&[data-href] {
cursor: pointer;
}

&:focus {
outline: 0;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -572,6 +572,10 @@ function AsyncLoadingExample() {
}
```

### Links

By default, interacting with an item in a SearchAutocomplete updates the input value. Alternatively, items may be links to another page or website. This can be achieved by passing the `href` prop to the `<Item>` component. Interacting with link items navigates to the provided URL and does not update the input value. See the [links](useListBox.html#links) section in the `useListBox` docs for details on how to support this.

## Internationalization

`useSearchAutocomplete` handles some aspects of internationalization automatically.
Expand Down
4 changes: 4 additions & 0 deletions packages/@react-aria/combobox/docs/useComboBox.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -671,6 +671,10 @@ function AsyncLoadingExample() {
}
```

### Links

By default, interacting with an item in a ComboBox selects it and updates the input value. Alternatively, items may be links to another page or website. This can be achieved by passing the `href` prop to the `<Item>` component. Interacting with link items navigates to the provided URL and does not update the selection or input value. See the [links](useListBox.html#links) section in the `useListBox` docs for details on how to support this.

## Internationalization

`useComboBox` handles some aspects of internationalization automatically.
Expand Down
24 changes: 24 additions & 0 deletions packages/@react-aria/gridlist/docs/useGridList.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import selectionDocs from 'docs:@react-stately/selection';
import statelyDocs from 'docs:@react-stately/list';
import focusDocs from 'docs:@react-aria/focus';
import checkboxDocs from 'docs:@react-aria/checkbox';
import utilsDocs from 'docs:@react-aria/utils';
import {HeaderInfo, FunctionAPI, TypeContext, InterfaceType, TypeLink, PageDescription} from '@react-spectrum/docs';
import {Keyboard} from '@react-spectrum/text';
import packageData from '@react-aria/gridlist/package.json';
Expand Down Expand Up @@ -484,6 +485,29 @@ This behavior is slightly different when `selectionBehavior="replace"`, where si
</div>
```

### Links

Items in a GridList may also be links to another page or website. This can be achieved by passing the `href` prop to the `<Item>` component. Links behave the same way as described above for row actions depending on the `selectionMode` and `selectionBehavior`.

```tsx example
<List aria-label="Links" selectionMode="multiple">
<Item href="https://adobe.com/" target="_blank">Adobe</Item>
<Item href="https://apple.com/" target="_blank">Apple</Item>
<Item href="https://google.com/" target="_blank">Google</Item>
<Item href="https://microsoft.com/" target="_blank">Microsoft</Item>
</List>
```

```css hidden
.list li[data-href] {
cursor: pointer;
}
```

#### Client side routing

The `<Item>` component works with frameworks and client side routers like [Next.js](https://nextjs.org/) and [React Router](https://reactrouter.com/en/main). As with other React Aria components that support links, this works via the <TypeLink links={utilsDocs.links} type={utilsDocs.exports.RouterProvider} /> component at the root of your app. See the [client side routing guide](routing.html) to learn how to set this up.

### Asynchronous loading

This example uses the [useAsyncList](../react-stately/useAsyncList.html) hook to handle asynchronous loading of data from a server. You may additionally want to display a spinner to indicate the loading state to the user, or support features like infinite scroll to load more data.
Expand Down
2 changes: 1 addition & 1 deletion packages/@react-aria/gridlist/src/useGridListItem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ export function useGridListItem<T>(props: AriaGridListItemOptions, state: ListSt
}
};

let linkProps = getSyntheticLinkProps(node.props);
let linkProps = itemStates.hasAction ? getSyntheticLinkProps(node.props) : {};
let rowProps: DOMAttributes = mergeProps(itemProps, linkProps, {
role: 'row',
onKeyDownCapture: onKeyDown,
Expand Down
4 changes: 0 additions & 4 deletions packages/@react-aria/link/docs/useLink.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,6 @@ function Link(props) {
<a
{...linkProps}
ref={ref}
href={props.href}
target={props.target}
style={{color: 'var(--blue)'}}>
{props.children}
</a>
Expand Down Expand Up @@ -136,8 +134,6 @@ function Link(props) {
<a
{...linkProps}
ref={ref}
href={props.href}
target={props.target}
style={{
color: props.isDisabled ? 'var(--gray)' : 'var(--blue)',
cursor: props.isDisabled ? 'default' : 'pointer'
Expand Down
20 changes: 17 additions & 3 deletions packages/@react-aria/link/src/useLink.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@

import {AriaLinkProps} from '@react-types/link';
import {DOMAttributes, FocusableElement} from '@react-types/shared';
import {filterDOMProps, mergeProps} from '@react-aria/utils';
import {RefObject} from 'react';
import {filterDOMProps, mergeProps, shouldClientNavigate, useRouter} from '@react-aria/utils';
import React, {RefObject} from 'react';
import {useFocusable} from '@react-aria/focus';
import {usePress} from '@react-aria/interactions';

Expand Down Expand Up @@ -62,6 +62,7 @@ export function useLink(props: AriaLinkOptions, ref: RefObject<FocusableElement>
let {pressProps, isPressed} = usePress({onPress, onPressStart, onPressEnd, isDisabled, ref});
let domProps = filterDOMProps(otherProps, {labelable: true, isLink: elementType === 'a'});
let interactionHandlers = mergeProps(focusableProps, pressProps);
let router = useRouter();

return {
isPressed, // Used to indicate press state for visual
Expand All @@ -70,12 +71,25 @@ export function useLink(props: AriaLinkOptions, ref: RefObject<FocusableElement>
...linkProps,
'aria-disabled': isDisabled || undefined,
'aria-current': props['aria-current'],
onClick: (e) => {
onClick: (e: React.MouseEvent<HTMLAnchorElement>) => {
pressProps.onClick?.(e);
if (deprecatedOnClick) {
deprecatedOnClick(e);
console.warn('onClick is deprecated, please use onPress');
}

// If a custom router is provided, prevent default and forward if this link should client navigate.
if (
!router.isNative &&
e.currentTarget instanceof HTMLAnchorElement &&
e.currentTarget.href &&
// If props are applied to a router Link component, it may have already prevented default.
!e.isDefaultPrevented() &&
shouldClientNavigate(e.currentTarget, e)
) {
e.preventDefault();
router.open(e.currentTarget, e);
}
}
})
};
Expand Down
Loading

0 comments on commit 15721e5

Please sign in to comment.