-
-
Notifications
You must be signed in to change notification settings - Fork 32.3k
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
[TreeView] Improve node registration and fix other issues #21574
Conversation
@material-ui/lab: parsed: +1.00% , gzip: +1.11% |
@joshwooding I know it's a draft. When you can get the chance, if you could like the issue(s) the change aims to solve, it would be 👌
Edit @eps1lon: Resolve size comparison issue in https://github.com/eps1lon/mui-contributor-dashboard/pull/9 |
I've tidied up tests as part of another change. |
48c5de8
to
cf75994
Compare
@@ -7,6 +7,7 @@ import Collapse from '@material-ui/core/Collapse'; | |||
import { fade, withStyles, useTheme } from '@material-ui/core/styles'; | |||
import { useForkRef } from '@material-ui/core/utils'; | |||
import TreeViewContext from '../TreeView/TreeViewContext'; | |||
import { DescendantProvider, useDescendant, useDescendantsInit } from '../TreeView/descendants'; |
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.
Using descendants allows us to get tree items in the correct order without reading children' props meaning we aren't so fragile and allow wrapped TreeItems.
@@ -990,27 +992,27 @@ describe('<TreeItem />', () => { | |||
fireEvent.keyDown(getByTestId('three'), { key: 'ArrowDown', shiftKey: true }); | |||
|
|||
expect(getByTestId('four')).toHaveFocus(); | |||
expect(container.querySelectorAll('[aria-selected=true]').length).to.equal(2); | |||
expect(container.querySelectorAll('[aria-selected=true]')).to.have.length(2); |
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.
Consistency changes.
@@ -864,10 +863,13 @@ describe('<TreeItem />', () => { | |||
|
|||
fireEvent.keyDown(getByTestId('one'), { key: '*' }); | |||
|
|||
expect(toggleSpy.args[0][1]).to.have.length(3); |
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 need to check the change handler here because eight will never have aria-expanded set due to a check when applying that attribute.
|
||
for (let i = 0; i < arr1.length; i += 1) { | ||
if (arr1[i] !== arr2[i]) return true; | ||
// To replace with Object.values() once we stop IE 11 support. |
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 didn't forget this time 😆 I'm sure I missed something else though :P
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 we really need Object.values? Isn't it trivial to do
-Object.values(obj).forEach(value => {
+Object.keys(obj).forEach(key => {
+ const value = obj[key]
})
@@ -77,6 +80,12 @@ const TreeView = React.forwardRef(function TreeView(props, ref) { | |||
state: 'selected', | |||
}); | |||
|
|||
const getChildren = (id) => |
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.
Bit worried about performance here due to all the looping. Something to think about I guess.
if (nodeIndex !== -1 && nodeIndex + 1 < visibleNodes.current.length) { | ||
return visibleNodes.current[nodeIndex + 1]; | ||
// If expanded get first child | ||
if (isExpanded(id) && getChildren(id).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.
I've got some changes planned in the future which mean we won't have to check children length here.
nodeMap.current[childId] = { ...currentChildMap, parent: id, id: childId }; | ||
}); | ||
}; | ||
nodeMap.current[id] = { id, index, parentId, expandable }; |
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.
Registering is a lot more simple now.
} | ||
}); | ||
nodeMap.current = newMap; | ||
cleanUpNodeMap(nodes); |
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.
unregistering nodes has also been simplified a lot.
); | ||
|
||
const mapFirstChar = (id, firstChar) => { | ||
firstCharMap.current[id] = firstChar; | ||
}; | ||
|
||
const prevChildIds = React.useRef([]); |
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.
Bye-bye, fragile code 👋
@@ -62,9 +62,7 @@ describe('<TreeView />', () => { | |||
); | |||
}); | |||
|
|||
// should not throw eventually or with a better error message | |||
// FIXME: https://github.com/mui-org/material-ui/issues/20832 | |||
it('crashes when unmounting with duplicate ids', () => { |
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.
🎉
import PropTypes from 'prop-types'; | ||
|
||
/** Credit: https://github.com/reach/reach-ui/blob/86a046f54d53b6420e392b3fa56dd991d9d4e458/packages/descendants/README.md | ||
* Modified slightly to suit our purposes. |
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.
Modifications are to allow the parentId to be read through this context. If we wanted to use the source we could use a second context. Not sure about IE11 support though.
cf75994
to
154c8f1
Compare
Work here is still relevant but reconsidering descendants is something to think about after the focus change: #21613 (comment) |
This comment has been minimized.
This comment has been minimized.
|
||
for (let i = 0; i < arr1.length; i += 1) { | ||
if (arr1[i] !== arr2[i]) return true; | ||
// To replace with Object.values() once we stop IE 11 support. |
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 we really need Object.values? Isn't it trivial to do
-Object.values(obj).forEach(value => {
+Object.keys(obj).forEach(key => {
+ const value = obj[key]
})
2dbbc84
to
3645d20
Compare
I have followed (at least) the PR section of the contributing guide.
Allows for more functionality in the future
Closes [TreeView] Unmount crashes React #20832 cc @eps1lon The test worked perfectly. I only realised I fixed it once the PR build failed :)
Removes limitation discussed during dogfeeding ([docs] Replace react-inspector with custom TreeView implementation #17662 (comment))
Closes #20092 (Including #20147 here to prevent merge conflicts)