-
Notifications
You must be signed in to change notification settings - Fork 4k
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
feat(Menu): Update to v1 API #382
Conversation
Linking #142 for fixing in this PR as well. |
Linking previous update PR #319. |
Current coverage is 98.61% (diff: 100%)@@ master #382 diff @@
==========================================
Files 99 101 +2
Lines 1438 1444 +6
Methods 0 0
Messages 0 0
Branches 0 0
==========================================
+ Hits 1418 1424 +6
Misses 20 20
Partials 0 0
|
|
||
if (isItem) { | ||
const onClick = (e) => { | ||
this.handleItemClick(e, i) | ||
if (isLink) this.handleItemClick(e, i) | ||
if (child.props.onClick) child.props.onClick(e, 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'll take this part from Accordion
component.
Can you review this fragment? It looks not good to me.
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 think we should add the click handler if the user is using subcomponents. We did this initially elsewhere, but there is just no reliable way to determine which children we should add it to.
React.Children can only loop through the top level children. If the user uses their own menu item component, then we have no reliable type
or displayName
to identify which components are menu items. They may also use a higher order component or decorator on the MenuItem, in which case the menu item is no longer a top level child but a nested child wrapped in the decorator.
Because of this, I think the only reliable way to pass props to children is when using the <Menu items={} />
prop. In this case, we know we can add props to every object in the array. It is the best way I know of to manage the parent-child coupling.
More here: https://facebook.github.io/react/docs/context.html#parent-child-coupling
EDIT
If the user uses subcomponents, they will just have to wire their own click handlers. The same is true for our <Dropdown options={} />
vs <Dropdown><Dropdown.Item /></Dropdown>
markup.
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.
Take a look on basic example of Menu. After click on item
it switches active
class to this item. I've implemented it like it is in Accordion
, but as you say this solution has problem.
I'm correctly understand that you suggest to use Content
? But, as you answered earlier:
Context is an advanced and experimental feature. The API is likely to change in future releases.
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 proposing two separate usage patterns.
items={} prop
My suggestion is that this usage will automatically manage the active item state:
<Menu items={[{}, {}, ...]} />
With this usage we can add the onClick handlers our selves and manage the active
prop on the MenuItem
s internally. We can do this easily since we must map over all the items
to create the MenuItems
.
Subcomponents
This usage would not self manage the active item. The user needs to implement their own onClick
handlers and set the active
prop:
class MenuExample extends Component {
handleItemClick = (name) => this.setState({ activeItem: name })
render() {
const { activeItem } = this.state
return (
<Menu>
<Menu.Item
active={activeItem === 'home'}
onClick={this.handleItemClick.bind('home')}
/>
<Menu.Item
active={activeItem === 'search'}
onClick={this.handleItemClick.bind('search')}
/>
<Menu.Item
active={activeItem === 'settings'}
onClick={this.handleItemClick.bind('settings')}
/>
</Menu>
)
}
}
These ideas can be improved on, but I think we should only auto manage the active state if you use the items
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.
It's reasonable, but it produce warning of ESLint 😞
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.
True, our eslint settings don't like bind
in an event handler. This can be solved easily like so:
onClick={() => this.handleItemClick('home')}
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 like a rebase was done from an out of date master. Update your local master, and the rebase from there. On the
EDIT |
no problem, one moment while i merge and force push... |
Give it a look and see if it is correct now. I have a copy of the original branch just in case I hosed this one. |
Looks okay, thanks 👍 Waiting for your reply there. |
|
For finishing Content and States part of docs I need #414. |
I paused the Form work to finish the augmentation. I hope to ship that today. I can do the popup next, or if you'd like to get a start on it we can tackle that one together. |
I've started the Tab component, #430. It is made of a Menu and Segments. I think if MenuItem's accept a name prop, it could help the Tab component. It would also help our onClick binding as we can callback with the Menu.Item name: export default class Menus extends Component {
handleItemClick = (e, name) => this.setState({ activeItem: name })
render() {
const { activeItem } = this.state
return (
<Menu>
<Menu.Item
name='browse'
active={activeItem === 'browse'}
onClick={this.handleItemClick}
>
Browse
</Menu.Item>
<Menu.Item
name='submit'
active={activeItem === 'submit'}
onClick={this.handleItemClick}
>
Submit
</Menu.Item>
<Menu.Menu position='right'>
<Menu.Item
name='signup'
active={activeItem === 'signup'}
onClick={this.handleItemClick}
>
Sign Up
</Menu.Item>
<Menu.Item
name='help'
active={activeItem === 'help'}
onClick={this.handleItemClick}
>
Help
</Menu.Item>
</Menu.Menu>
</Menu>
)
}
} It can be used as shorthand props to generate the menu item text. Same example as above but with shorthand MenuItem child text: export default class Menus extends Component {
handleItemClick = (e, name) => this.setState({ activeItem: name })
render() {
const { activeItem } = this.state
return (
<Menu>
<Menu.Item
name='browse'
active={activeItem === 'browse'}
onClick={this.handleItemClick}
/>
<Menu.Item
name='submit'
active={activeItem === 'submit'}
onClick={this.handleItemClick}
/>
<Menu.Menu position='right'>
<Menu.Item
name='signup'
active={activeItem === 'signup'}
onClick={this.handleItemClick}
/>
<Menu.Item
name='help'
active={activeItem === 'help'}
onClick={this.handleItemClick}
/></Menu.Menu>
</Menu>
)
}
} Lastly, it works well with a shorthand items array where the objects are spread on each item. It could also be used to propagate the onClick to the Menu when using an array of items. This would be an AutoControlledComponent now. The active item can be self managed. Optionally, a user could override the active item with an const items = [
{ name: 'browse' },
{ name: 'submit' },
{ name: 'signup' },
{ name: 'help' },
]
export default class Menus extends Component {
handleClick = (e, name) => {
// do something with the clicked item
}
render() {
return (
<Menu onClick={this.handleClick} items={items} />
)
}
} |
Looks pretty, take it work. |
Gah, yep! There are hardcoded The One idea might be setting a global platform dependent // config.js
compiler_globals: {
__PATH_SEP__: JSON.stringify(path.sep),
} Then we could use |
Merged #435, give that a shot! |
In addition to calling back with the menu item name onClick, let's also call back with the item index: handleClick(e, { name, index}) {
//...
}
<Menu.Item onClick={this.handleClick} /> This will help other components like Tab and Accordion use the Menu to control their activeIndex. |
How I can get <Menu>
<Menu.Item>A</Menu.Item>
<Menu.Item>B</Menu.Item>
</Menu> |
764d371
to
b5e96d3
Compare
I've updated this to the latest master. I also fixed the existing tests and added missing sub component tests. It should be all set for continuing with the docs. Since I squashed and force pushed to clean it up a bit, you'll probably want to blow away your local branch in favor of this one. I did not make any major updates to the functionality. So, the Menu itself is still in progress. |
Thanks much, I'll think I'll finish docs on this weekend. |
return <div>{menus}</div> | ||
} | ||
|
||
export default ColoredInvertedMenus |
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.
@levithomason what you think about this?
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.
The loop is perfectly acceptable, but let's not show use of the private _meta
prop. I don't want users knowing/using that. I think putting it in the docs will encourage use of it. Instead, let's just list the colors in an array explicitly.
DocsUnbelievable, but it is finished ✌️ We need review for them. TestsTests will be finished tomorrow. And final review will there soon 👍 ShorthandsDiscuss? Menu.MenuI think, we don't need provide Menu
const items [
{name: 'Open'},
{name: 'Save'},
]
<Menu items={items} onItemClick={handler} /> const items [
{name: 'Open', onClick: onOpenClick},
{active: true, name: 'Save', onClick: onSaveClick},
]
<Menu items={items} />
|
Docs - Wow, great work! Will get a review soon as I can. |
TestsThere are here 🚢 ShorthandsI'll implement and add docs with tests soon 😪 |
Will review this today, thanks for the massive amount of work here! |
37f6873
to
b8d0d14
Compare
Heads up, doing a final review and some minor tweaks. Hope to merge this today. |
Latest updates: Start Case Name propUpdated Dropdown Item UpdatedCompleted TODO for Dropdown header usage. Also, reversed the augmentation from Colored MenusMapped over an array of colors to make examples a little more concise. More importantly, to not expose the MiscI made some trivial updates to the docs in terms of verbiage and/or organization. |
🎉 This is great, thanks a million. We can do shorthand separately since this PR was so massive. |
Released in |
WIP
Update Menu to v1 API