-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for routerOptions and useHref #5864
Conversation
Build successful! 🎉 |
# Conflicts: # packages/@react-spectrum/breadcrumbs/test/Breadcrumbs.test.js # packages/@react-spectrum/combobox/test/ComboBox.test.js # packages/@react-spectrum/link/test/Link.test.js # packages/@react-spectrum/list/test/ListView.test.js # packages/@react-spectrum/listbox/test/ListBox.test.js # packages/@react-spectrum/picker/test/Picker.test.js
Build successful! 🎉 |
@@ -494,4 +494,8 @@ export class SelectionManager implements MultipleSelectionManager { | |||
isLink(key: Key) { | |||
return !!this.collection.getItem(key)?.props?.href; | |||
} | |||
|
|||
getItemProps(key: Key) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adding this to selection manager feels a bit weird, but not sure where else to put it. useSelectableCollection
and useSelectableItem
don't currently receive the collection as props, except via SelectionManager
...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
agreed, it's a bit odd, however, we already have 'isLink' in here, which is almost the same thing and is only tangentially related to selection
would it make more sense to just return the collection and then handle this specific logic outside?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
well, the original idea was that the MultipleSelectionManager
interface could have multiple implementations, perhaps not even using collections under the hood. So if we expose the collection from the interface that will force other implementations to also use collections.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that makes sense :-/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can keep discussing, but approving so we can get nightlies out sooner rather than later
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Docs/code look good to me, will test the apps once they get built on main. Does the remix one get built somewhere? I tried running it locally but got a Invalid URL
error. Otherwise just one small comment but happy to get this merged as is
export function useLinkProps(props: LinkDOMProps) { | ||
let router = useRouter(); | ||
return { | ||
href: props?.href ? router.useHref(props?.href) : undefined, | ||
target: props?.target, | ||
rel: props?.rel, | ||
download: props?.download, | ||
ping: props?.ping, | ||
referrerPolicy: props?.referrerPolicy | ||
}; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
minor nit but it almost feels like this useRouter call should be in filterDOMProps
instead of being a separate function if only to guard against cases where both filterDOMProps
and useLinkProps
are called and the props from useLinkProps
need to be merged after the ones from filterDOMProps
. Is there something I'm missing here as to why this is a separate function?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
because filterDOMProps isn't a hook so it cannot call other hooks... :/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ahhh, right ugh
# Conflicts: # packages/@adobe/react-spectrum/src/index.ts # packages/@react-spectrum/breadcrumbs/test/Breadcrumbs.test.js # packages/@react-spectrum/combobox/test/ComboBox.test.js # packages/@react-spectrum/link/test/Link.test.js # packages/@react-spectrum/list/test/ListView.test.js # packages/@react-spectrum/listbox/test/ListBox.test.js # packages/@react-spectrum/picker/test/Picker.test.js # packages/@react-types/shared/src/dom.d.ts
Build successful! 🎉 |
# Conflicts: # packages/@react-aria/listbox/src/useOption.ts # packages/@react-aria/menu/src/useMenuItem.ts
Build successful! 🎉 |
Build successful! 🎉 |
## API Changes
unknown top level export { type: 'any' } @react-aria/utilsRouterProvider RouterProvider {
children: ReactNode
- navigate: (string) => void
+ navigate: (Href, RouterOptions | undefined) => void
+ useHref?: (Href) => string
} useFormReset-
+useLinkProps {
+ props: LinkDOMProps
+ returnVal: undefined
+} @react-stately/selectionMultipleSelectionManager MultipleSelectionManager {
canSelectItem: (Key) => boolean
childFocusStrategy: FocusStrategy
clearSelection: () => void
disabledBehavior: DisabledBehavior
disabledKeys: Set<Key>
disallowEmptySelection?: boolean
extendSelection: (Key) => void
firstSelectedKey: Key | null
focusedKey: Key
+ getItemProps: (Key) => any
isDisabled: (Key) => boolean
isEmpty: boolean
isFocused: boolean
isLink: (Key) => boolean
isSelected: (Key) => boolean
isSelectionEqual: (Set<Key>) => boolean
lastSelectedKey: Key | null
replaceSelection: (Key) => void
select: (Key, PressEvent | LongPressEvent | PointerEvent) => void
selectAll: () => void
selectedKeys: Set<Key>
selectionBehavior: SelectionBehavior
selectionMode: SelectionMode
setFocused: (boolean) => void
setFocusedKey: (Key, FocusStrategy) => void
setSelectedKeys: (Iterable<Key>) => void
setSelectionBehavior: (SelectionBehavior) => void
toggleSelectAll: () => void
toggleSelection: (Key) => void
}
SelectionManager SelectionManager {
canSelectItem: (Key) => void
childFocusStrategy: FocusStrategy
clearSelection: () => void
constructor: (Collection<Node<unknown>>, MultipleSelectionState, SelectionManagerOptions) => void
disabledBehavior: DisabledBehavior
disabledKeys: Set<Key>
disallowEmptySelection: boolean
extendSelection: (Key) => void
firstSelectedKey: Key | null
focusedKey: Key
+ getItemProps: (Key) => void
isDisabled: (Key) => void
isEmpty: boolean
isFocused: boolean
isLink: (Key) => void
isSelected: (Key) => void
isSelectionEqual: (Set<Key>) => void
lastSelectedKey: Key | null
rawSelection: ISelection
replaceSelection: (Key) => void
select: (Key, PressEvent | LongPressEvent | PointerEvent) => void
selectAll: () => void
selectedKeys: Set<Key>
selectionBehavior: SelectionBehavior
selectionMode: SelectionMode
setFocused: (boolean) => void
setFocusedKey: (Key | null, FocusStrategy) => void
setSelectedKeys: (Iterable<Key>) => void
setSelectionBehavior: (SelectionBehavior) => void
toggleSelectAll: () => void
toggleSelection: (Key) => void
}
|
Closes #5395, closes #5335, relates to #5476
This improves integration with client side routers by introducing two new APIs:
routerOptions
prop on each component that supports links. This is an opaque object that React Aria simply passes through to the router. It can be used for options like controlling scroll behavior, using replaceState instead of pushState, or any other features offered by a router. It is passed to thenavigate
function provided toRouterProvider
as a second argument in addition to thehref
.useHref
prop forRouterProvider
which is used to convert anhref
provided to a link component to a nativehref
. For example, a router might accept hrefs relative to a base path, or offer additional custom ways of specifying link destinations. The originalhref
specified on the link is passed to thenavigate
function of theRouterProvider
, anduseHref
is used to generate the full native href to put on the actual DOM element.Both of these APIs work with TypeScript to enable autocomplete and type checking for the router options and also the href. To configure it, you can use TypeScript module augmentation to specify the
RouterOptions
type:Do that once in your app (maybe where you setup RouterProvider), and all link components in React Aria/RSP will use those options.
To do