-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
RAC Tree #5756
RAC Tree #5756
Conversation
…derProps functions
…tence of content nodes
now that we are iterating over every tree item, we need to check if a rows parent is in the expanded key AND is also in the flattened row list. This is essentially checking if every parent above it is expanded as well since that is the only way its immediate parent would be in the flattened row list
…ridListItem this is because we need to stop the grid list keyboard navigation if we are going to perform an expand or collapse but cant do so since it is a capturing listener. An alternative is to copy all the code from useGridListItem as is to useTreeGridListItem but that can be discussed.
Build successful! 🎉 |
Build successful! 🎉 |
// TODO: missing selectionBehavior, hasAction and allowsSelection data attribute equivalents (available in renderProps). Do we want those? | ||
data-expanded={hasChildRows ? isExpanded : undefined} |
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.
Table is similar here in that it doesn't have data attributes for the mentioned attributes which feels like it makes sense, not sure how helpful it would be to expose the above as data attributes
Build successful! 🎉 |
Build successful! 🎉 |
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.
Looks great!
The only unexpected behavior I see is that typeahead has unpredictable behavior.
* and selection. | ||
*/ | ||
const _Tree = /*#__PURE__*/ (forwardRef as forwardRefType)(Tree); | ||
export {_Tree as Tree}; |
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.
Should this be called TreeView to better match the ARIA APG https://www.w3.org/WAI/ARIA/apg/patterns/treeview/
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.
happy to change it, mainly was concerned about if the RSP tree would be called TreeView too haha. Anyone else have any thoughts? Maybe TreeGrid (except it is only one column...)
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.
I think it's fine if they have the same name. IMO: TreeView > Tree > TreeGrid
Co-authored-by: Reid Barber <reid@reidbarber.com>
@reidbarber what specifically did you run into for the typeahead? |
@LFDanLu Looks like I was just pressing keys again before the cooldown period ended. No issues there, ignore that! |
Build successful! 🎉 |
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.
first pass through tests
@@ -199,8 +246,9 @@ export function useGridListItem<T>(props: AriaGridListItemOptions, state: ListSt | |||
'aria-colindex': 1 | |||
}; | |||
|
|||
// TODO: should isExpanded and hasChildRows be a item state that gets returned by the hook? |
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.
seems useful to me
// TODO: would be nice if the collection row information differentiated between childNodes vs childItems | ||
// so we didn't have to keep iterating through info, perhaps make the user pass a prop to TreeItem for childItems/hasChildRows even in the static case? | ||
updatedExpandedKeys = new Set([...collection].filter(row => { | ||
return row.props.childItems || [...collection.getChildren(row.key)].filter(child => child.type === 'item').length > 0; |
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.
when you construct the collection, can you just mark the item node?
// TODO does this need ref or context? Its only used to shallowly render the Content node... If it was a more generic collection component then I could see an argument for it | ||
// having those | ||
function TreeItemContent(props: TreeItemContentProps) { |
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.
what would the ref point to? there isn't an actual dom node corresponding to this right?
added test util and updating some tests for consistency
if ('expandedKeys' in state && document.activeElement === ref.current) { | ||
if ((e.key === EXPANSION_KEYS['expand'][direction]) && state.selectionManager.focusedKey === node.key && hasChildRows && state.expandedKeys !== 'all' && !state.expandedKeys.has(node.key)) { | ||
state.toggleKey(node.key); | ||
e.stopPropagation(); | ||
return; | ||
} else if ((e.key === EXPANSION_KEYS['collapse'][direction]) && state.selectionManager.focusedKey === node.key && hasChildRows && (state.expandedKeys === 'all' || state.expandedKeys.has(node.key))) { | ||
state.toggleKey(node.key); | ||
e.stopPropagation(); | ||
return; | ||
} | ||
} | ||
|
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.
Need to modify the keyboard nav logic here for expansion and stuff since this is a capturing listener and thus can't be stopped in the useTreeGridListItem hook. If we want to keep this hooks clean from tree grid stuff, I can copy pasta the code here into useTreeGridListItem. Alternatively, I could make this hook and useGridList hook keep all the grid specific stuff and get rid of the TreeGridList hooks
Build successful! 🎉 |
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.
Giving preliminary approval. Is it ok to make the rest followup? I'd like to get this into testing.
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.
LGTM, still have the question about naming, but we can change that later if we need to.
Build successful! 🎉 |
## API Changes
unknown top level export { type: 'any' } @react-aria/gridlistuseGridListItem useGridListItem<T> {
props: AriaGridListItemOptions
- state: ListState<T>
+ state: ListState<T> | TreeState<T>
ref: RefObject<FocusableElement>
returnVal: undefined
} @react-aria/treeuseTreeGridListchanged by:
-
+useTreeGridList<T> {
+ props: AriaTreeGridListOptions<T>
+ state: TreeState<T>
+ ref: RefObject<HTMLElement>
+ returnVal: undefined
+} useTreeGridListItemchanged by:
-
+useTreeGridListItem<T> {
+ props: AriaTreeGridListItemOptions
+ state: TreeState<T>
+ ref: RefObject<FocusableElement>
+ returnVal: undefined
+} AriaTreeGridListOptions-
+AriaTreeGridListOptions<T> {
+ keyboardDelegate?: KeyboardDelegate
+} it changed:
AriaTreeGridListProps+AriaTreeGridListProps<T> {
+} TreeGridListAria-
+TreeGridListAria {
+ gridProps: DOMAttributes
+} it changed:
TreeGridListProps+TreeGridListProps<T> {
+} AriaTreeGridListItemOptions-
+AriaTreeGridListItemOptions {
+ node: Node<unknown>
+} it changed:
TreeGridListItemAria-
+TreeGridListItemAria {
+ descriptionProps: DOMAttributes
+ gridCellProps: DOMAttributes
+ rowProps: DOMAttributes
+} it changed:
@react-stately/treeTreeProps TreeProps<T> {
-
+ disabledBehavior?: DisabledBehavior
} it changed:
TreeState TreeState<T> {
collection: Collection<Node<T>>
disabledKeys: Set<Key>
- expandedKeys: Set<Key>
+ expandedKeys: 'all' | Set<Key>
selectionManager: SelectionManager
- setExpandedKeys: (Set<Key>) => void
+ setExpandedKeys: ('all' | Set<Key>) => void
toggleKey: (Key) => void
} it changed:
TreeCollection TreeCollection<T> {
at: (number) => void
constructor: (Iterable<Node<T>>, {
- expandedKeys?: Set<Key>
+ expandedKeys?: 'all' | Set<Key>
}) => void
getFirstKey: () => void
getItem: (Key) => void
getKeyAfter: (Key) => void
getKeys: () => void
getLastKey: () => void
size: any
undefined: () => void
}
|
Merged for testing, feel free to continue reviewing off this PR if need be. I'll capture the followups in a ticket |
@@ -26,13 +29,13 @@ export interface TreeState<T> { | |||
readonly disabledKeys: Set<Key>, | |||
|
|||
/** A set of keys for items that are expanded. */ | |||
readonly expandedKeys: Set<Key>, | |||
readonly expandedKeys: 'all' | Set<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.
changing this type could potentially be a breaking change. if someone was relying on expandedKeys being a set (and doing things like expandedKeys.has('foo')
on it), then the 'all'
value would cause an error to be thrown.
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.
ah, good call, thats a bit annoying since it would be good for this to be consistent with our expandable rows table api... I can get rid of this 'all'
support for now, but I guess I would have to create a separate tree state hook then to support 'all'
, thoughts?
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.
where did the requirement for all
come from? We don't have UI for an "expand all" button right?
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.
we don't have a hard requirement for all
but it was added to the expandable table rows to help with the eventual async case where a team may want all their rows to be auto expanded as they are loaded in
let renderProps = useRenderProps({ | ||
...props, | ||
id: undefined, | ||
children: item.rendered, |
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.
do tree items support render props? seems like that could conflict with the function for providing children?
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.
oh hm, I hadn't really considered that, in my mind I figured users would use the renderProps that TreeItemContent provides. I'll see if I can get rid of the renderProps function for TreeItem entirely
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.
Ah, actually I've already have the types setup such that the children of the TreeItem doesn't include the renderProps children definition. I've gotten rid of the ((item: T) => ReactElement)
part of it since users should use a Collection
for the dynamic case
Closes
✅ Pull Request Checklist:
📝 Test Instructions:
🧢 Your Project: