-
Notifications
You must be signed in to change notification settings - Fork 231
Conversation
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.
Still reviewing list/index.test.js, but wanted to send you this ahead of time.
packages/list/ListItem.js
Outdated
ListItem.propTypes = { | ||
childrenTabIndex: PropTypes.number, | ||
className: PropTypes.string, | ||
primaryText: PropTypes.string, |
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 primaryText and secondaryText should be element
, because they may want to wrap them in or something else.
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.
actually it might be oneOfType(element, string)
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 you give me an example? does MDC Web allow for text to be other elements?
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.
There might be a text formatter or date formatter out there that you would use as a component. IE:
<ListItem
primaryText={<DateFormatter date={new Date()} />} />
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.
👍
packages/list/index.js
Outdated
ref: (listItem) => !this.listItems_[index] && this.listItems_.push(listItem), | ||
...otherProps, | ||
}, | ||
{className: this.getListItemClasses_(index)}, |
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.
you can wrap these in one object:
{
updateClassList: this.updateListItemClassList,
ref: (listItem) => !this.listItems_[index] && this.listItems_.push(listItem),
className: this.getListItemClasses_(index)
childrenTabIndex: this.state.listItemChildrenTabIndex[index],
...otherProps,
},
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 don't really know why but childrenTabIndex
doesn't seem to be propagating if we do it this way
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.
is it included in otherProps? If so, otherProps.childrenTabIndex will take precedence
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.
got it, works now!
packages/list/ListItem.js
Outdated
...otherProps | ||
} = graphic.props; | ||
const props = { | ||
tabIndex: tabIndex != undefined ? this.props.childrenTabIndex : -1, |
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.
This is strange...shouldn't they be able to override tabIndex if they pass it through the graphic element? I don't see this logic in MDC Web list. Is this something that needs to be here?
Also !==
And if it is undefined
doesn't the defaultProp take its place?
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.
Yeah this is kinda weird...basically there are elements whose tabIndex
we want the parent list item to be able to toggle between 0 and -1 (like button/icon/input/link), and elements whose tabIndex
should always be -1 (like span/div/leading icons).
In MDC Web we just set button
and a
elements to be togglable, and all other elements to have tabIndex
always -1. I think MDC Web is missing some functionality, for example icons should be togglable too.
So I wanted to make it up to the user to set the child elements to be togglable, while the rest default to be untogglable (tabIndex
always -1). I think the idea is to completely control tabIndex
within the list, meaning the user cannot override it. This is for accessibility. I redid it after splitting out the graphic/text/meta out into subcomponents, let me know what you think.
packages/list/ListItem.js
Outdated
renderText(primaryText, secondaryText) { | ||
if (secondaryText) { | ||
return ( | ||
<span className='mdc-list-item__text'> |
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 we should make the follow separate elements that we provide:
mdc-list-item__text <ListItemText />
mdc-list-item__primary-text <ListItemPrimaryText />
mdc-list-item__secondary-text <ListItemSecondaryTexst />
mdc-list-item__graphic <ListItemGraphic />
mdc-list-item__meta <ListItemMeta />
OR we allow the user to do this both ways. So we can keep props inline, and provide the above elements, but then we would need to render children too.
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 broke them out into 3 subcomponents because have 3 separate text components seemed overkill
packages/list/index.js
Outdated
} | ||
|
||
componentDidMount() { | ||
for (let i = 0; i < this.listItems_.length; i++) { |
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.
make this a forEach
. It reads better.
packages/list/index.js
Outdated
} | ||
|
||
getListItemIndexOfElement_ = (element) => { | ||
for (let i = 0; i < this.listItems_.length; i++) { |
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 you're using a for
here, but what if we add the polyfill for findIndex? I remember you doing this somewwhere else too.
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 polyfill?
packages/list/index.js
Outdated
removeAttributeForElementIndex: (index, attr) => { | ||
const listItemAttributes = this.state.listItemAttributes; | ||
attr = attr === 'tabindex' ? 'tabIndex' : attr; | ||
listItemAttributes[index][attr] = null; |
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 you actually have to remove it from the object?
toggleCheckbox: (index) => { | ||
const listItem = this.listItems_[index]; | ||
if (listItem) { | ||
listItem.toggleCheckbox(); |
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.
still need to implement toggleCheckbox()
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.
Yeah I think I'll file an issue and work on it separately
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.
packages/list/index.js
Outdated
if (index >= 0) { | ||
this.foundation_.handleKeydown(e, true /* isRootListItem is true if index >= 0 */, index); | ||
} | ||
this.props.onKeyDown(e); |
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.
Move the props.onEvent methods above. I think we should allow the developer to setup the dom before we do anything if needed. I cant think of why they would need to, but that's the pattern I've been following. What are your 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.
same with click, focus, and blur
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.
SGTM
packages/list/index.js
Outdated
|
||
getListItemClasses_(index) { | ||
const {listItemClassList} = this.state; | ||
return listItemClassList[index] ? classnames(Array.from(listItemClassList[index])) : ''; |
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 you also want to get the listItem.className and merge it here.
Codecov Report
@@ Coverage Diff @@
## master #339 +/- ##
==========================================
+ Coverage 97.29% 97.49% +0.19%
==========================================
Files 40 45 +5
Lines 1514 1714 +200
Branches 164 191 +27
==========================================
+ Hits 1473 1671 +198
- Misses 41 43 +2
Continue to review full report at Codecov.
|
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.
testing some things in the screenshot tests...I will share if I find anything interesting.
packages/list/ListItemGraphic.js
Outdated
const graphicProps = { | ||
className: this.classes, | ||
role: 'presentation', | ||
tabIndex: tabbableOnListItemFocus ? this.props.tabIndex : -1, |
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.
Why not just use tabIndex here if they pass a tabIndex in from props? Why do we need this special prop? This goes for all the other components that have this prop.
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.
Talked offline: this is to determine whether the graphic tabIndex should switch from -1 to 0 when the list item is focused or if its tabIndex should always be -1.
packages/list/ListItemGraphic.js
Outdated
|
||
const graphicProps = { | ||
className: this.classes, | ||
role: 'presentation', |
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.
If the user passes in a different role, does this go with their configuration? We shouldn't overwrite.
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.
It looks like this works:
<ListItemGraphic graphic={<MaterialIcon icon='folder'/>} role='menu'/>
But this looks more intuitive:
<ListItemGraphic graphic={<MaterialIcon icon='folder' role='menu'/>}/>
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.
Good point, removed override.
packages/list/ListItemMeta.js
Outdated
export default class ListItemMeta extends Component { | ||
get classes() { | ||
const {className, meta} = this.props; | ||
return classnames('mdc-list-item__meta', className, meta.className); |
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 if meta.className is undefined, it will print undefined
in the rendered class
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.
Just kidding...tested this. Its fine
packages/list/ListItemMeta.js
Outdated
tabbableOnListItemFocus: PropTypes.bool, | ||
className: PropTypes.string, | ||
tabIndex: PropTypes.number, | ||
meta: PropTypes.element, |
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.
this should also be oneOfType(element, string)
packages/list/ListItemText.js
Outdated
import PropTypes from 'prop-types'; | ||
import classnames from 'classnames'; | ||
|
||
export default class ListItemText extends Component { |
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'm thinking we could even break this into . Not sure what you think. We'd also then need to provide another component that wraps the 2 (the element with .mdc-list-item__text
). This might be simpler, so I'm all for it and just wanted to get your 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.
Talked offline, will keep as is unless there proves to be a need otherwise
packages/list/index.js
Outdated
}; | ||
|
||
componentDidMount() { | ||
for (var key in this.listItems_) { |
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.
use let
-- its just so in right now
packages/list/index.js
Outdated
const {listItemAttributes} = this.state; | ||
listItemAttributes[key] = { | ||
'aria-selected': false, | ||
'tabIndex': this.listItemIndices_[key] === 0 ? 0 : -1, |
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 if someone manually changes the tabIndex to something other than 0 or -1...in this case it'll default to -1
packages/list/index.js
Outdated
...otherProps | ||
} = listItem.props; | ||
|
||
const keyOrIndex = key || index; |
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.
Why do you have 1 or the other? I think the key should always just be the index. If you do this, you should be able to remove listItemIndicies
.
packages/list/index.js
Outdated
setAttributeForElementIndex: (index, attr, value) => { | ||
const {listItemAttributes} = this.state; | ||
attr = attr === 'tabindex' ? 'tabIndex' : attr; | ||
const key = this.getListItemKeyFromIndex_(index); |
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 the key should always be the index. Instead of this, cant you just do this.listItems_[key]
?
packages/list/index.js
Outdated
|
||
getListItemIndexOfTarget_ = (eventTarget) => { | ||
// Find the first ancestor that is a list item. | ||
const listItemElement = eventTarget.closest('.mdc-list-item'); |
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.
not supported on IE :(
https://developer.mozilla.org/en-US/docs/Web/API/Element/closest
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.
😩
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.
If it helps, the mdc-dom package's ponyfill module has this function
@@ -27,6 +27,11 @@ import classnames from 'classnames'; | |||
export default class ListItem extends Component { | |||
listItemElement_ = React.createRef(); | |||
|
|||
componentDidMount() { | |||
const {init} = this.props; |
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.
just add a defaultProp for init
as an empty method. You don't need to guard against it on line 32.
init();
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.
If we set a default prop here the actual prop doesn't override it....
packages/list/README.md
Outdated
className | String | Classes to be applied to the list item element | ||
childrenTabIndex | Number | Tab index to be applied to all children of the list item | ||
init | Function() => void | Callback to initialize the list item on mount |
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 its actually Callback executed when list item mounts
@@ -5,7 +5,7 @@ import {shallow, mount} from 'enzyme'; | |||
import List from '../../../packages/list'; | |||
import {ListItem} from '../../../packages/list'; | |||
|
|||
suite.only('List'); | |||
suite('List'); |
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.
add a test for removing a list item and adding a list item.
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.
return this.getIndexOfListItemElement_(target); | ||
} | ||
|
||
onKeyDown = (e) => { |
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.
move onKeyDown, onClick, onFocus, and onBlur into the renderListItem
, and pass the index. We can then remove getListItemIndexOfTarget_
.
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.
Fixes #189