-
Notifications
You must be signed in to change notification settings - Fork 3.6k
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
DropdownButton, SplitButton, DropdownMenu, MenuItem Rewrite #1096
Conversation
9f0c4d1
to
fca0be7
Compare
woohoo! gonna dig into this a bit tomorrow, I have a few cases at work where I can try it out. |
Digging deeper this may be complicated pending the outcome of #419 (comment) |
👏 |
} | ||
|
||
handleDocumentClick(event) { | ||
let inTree = domUtils.isNodeInTree(event.target, React.findDOMNode(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.
I think this is probably now a duplicate of domUtils.contains
which was added recently-ish
gonna try and help out with some docs tomorrow if I get some time :) |
Do we have further consensus on whether we are pushing forward with the onSelect event, or going to try a different approach? |
} | ||
} | ||
|
||
bindRootCloseHandler() { |
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 would be great to just use RootCloseWrapper here, but I don't think it'll work as it adds a wrapping div, @taion any 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.
w/r/t RootCloseWrapper
, I originally wrote it to use a wrapping div
because I couldn't be sure that whatever custom popover I wrapped it with wouldn't do something dumb with onClick
.
For something like this where we control what gets rendered (i.e. with the outer-most ul
), I'd modify RootCloseWrapper
to have a separate path that just injects the onClick
prop instead of using the wrapping div
.
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.
Thats sort of the rub here as well, folks can now provide custom menu components, so we don't know for certain that the component will handle it...
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.
#render()
here always renders a ul
as the outer-most DOM node, and we control it directly, no? Unless I'm misreading this code. i.e. we can just inject onClick
into that ul
from RootCloseWrapper
painlessly.
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.
bah sorry yes. I was conflating this question along with another one about whether it makes sense to push the root click to the DropdownBase instead of the menu, so all menus' benefit from it.
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 sorry, I've barely gotten started reading through the rest of the PR.
How much does the rendering break if we add the wrapping div
?
@jquense I like your earlier proposal for the events, it dramatically simplifies things. |
const TOGGLE_REF = 'toggle-btn'; | ||
|
||
export default class DropdownBase extends React.Component { | ||
constructor(props, Toggle=DropdownToggle) { |
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 believe the 2nd param to React.Component#constructor
is supposed to be context
.
Could we just use this.constructor.Toggle
below? Or set Toggle
on the prototype?
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.
On second thought, this.constructor.Toggle
will break everyone using IE <= 10 because static inheritance won't work there, so I'd suggest putting Toggle
on the prototype, e.g. below do SplitButton.prototype.Toggle = SplitToggle
.
This is super cool. |
labelledBy: this.props.id | ||
}; | ||
|
||
if (menu === 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.
cc @jquense
This is actually the opposite of what we decided to do for Modal
, i.e. the support for custom modal dialogs is going into react-overlays, while the R-B Modal
intentionally has fairly limited support (and a different API) for specifying a custom modal dialog class.
It might be nice to be consistent here if possible.
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 was thinking about that myself and i am a bit torn about this one. If there is a more generic dropdown implementation that could be refactored out, its probably to early to know what that'd look like yet. On the other hand i think the level of customizability here is probably on par with what you could do with bootstrap proper. We, for instance gut the built in dropdown (in our non react projects), and essentially just use the styles. this api would let me do that in react, which I really appreciate.
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.
Sure - the right answer might just be to make the R-B Modal
's customDialogComponent
API look a little more like this. I don't think it'd affect anybody deciding between using R-B Modal
and react-overlays, but it'd make things line up better between R-B modals and dropdowns.
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.
Ya definitely, as it is, the custom dialog prop is sort of a 'good enough' solution for the time anyway. I'm all for consistency
@jquense With that PR complete did you see anything else that's needed before we bring this in? If it's complete I can do a squash and rebase |
@mtscout6 I think we still need to fix the way we pass in |
So there is a good, point here: #526 (comment) the current PR will break users using a custom menuItem, since the extractors look for not known types and assume they are menu's. We can always say that these cases need to have a menu wrapped around them, or perhaps create a more public api for telling the dropdown about types. |
@jquense An alternative might be to use something like |
@taion i would like to keep the current way if possible, it seems the more ergonomic of the two api (to me anyway). One issue with that approach tho is that you'd have to do something similar for the Button and Toggle components as well and that seems ugly... Ultimately the issue is that the Dropdown really needs to know what things are menu items, or toggles, or menus. The most straight forward way to me is just to duck type it with a static property or something, not super elegant. |
That makes sense. What do you think of doing the same for |
seems reasonable to me, tho that case is a little different, since the user is almost always going to specify a custom dialog, whereas here they may just specify a menu to add some classes or something. The other thing might be that maybe we can jsut get rid of that feature on the modal completely, and point ppl to react-overlays if they need something more custom...I still need to see what the diff is between that and our implementation tho, before I can say its easy to do. |
To make sure I'm not misunderstanding you, is your proposal that the
If the user does (1), then we use the explicitly labeled components. If the user does (2), then everything proceeds per the default. The alternatively would be something like exposing Thinking a little more, I'm not sure which semantically feels better. I like the elegance of specifying everything under |
To add to that, one difference between this and the API for This is a bit different in that the different |
I think maybe some sort of |
examples of what I am thinking of... <DropdownButton>
<Button bsRole='toggle' >open</Button>
<CustomMenu bsRole='menu'>
<MenuItem>Item 2</MenuItem>
</CustomMenu>
</DropdownButton> or <NavItem><Link bsRole='link'>client route</Link></NavItem> I want to say that whatever the API is it is really an escape hatch. Most folks shouldn't need this sort of behavior, In general it will be other library authors (like react-router-bootstrap). In this particular case, I think the "magic" is in assuming certain components are Menus. It seems like the perhaps we should be explicitly checking for menus and toggles, and just assume everything else is a MenuItem, which preserves the current behavior. essentially a component has two "modes" for dealing with children, if a bsRole is defined on any child, then there is a strict whitelist of components allowed, only children with a role, and only whitelisted roles for that component. Otherwise it just does its default, such as wrapping children in a menu. |
ok I checked a few things off I think, Are more pending items before we merge this? In liee of general onSelect documentation perhaps we should document controlled/uncontrolled props in getting started or something? If so does that block the PR here? |
anything else here? LGTM otherwise (baring some commit squashing)... |
Looks good to me, though I don't have time to do the squashing for this before tomorrow. |
@@ -21,6 +21,9 @@ if (options.debug) { | |||
} | |||
|
|||
export default _.extend({}, baseConfig, { | |||
|
|||
devtool: options.debug ? 'source-map' : 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.
Probably shouldn't change this here either.
This is really cool BTW. Thanks so much for all the work you've put into this - the new "custom" API is fantastic. |
Ya it really is super sweet and going to save me a ton of work in the long run, thanks @mtscout6 ! |
I'm going to give the rebase and squash a go right now. |
c22680f
to
0e161f4
Compare
Well, that rebase went quicker than I was expecting. |
😢 Linting killed it, I'll get that fixed. Give me a few minutes. |
…ely rewritten Adds: - Keyboard Navigation - Aria properties for Assistive Technology - Option to use custom menu with any of the dropdown variations - `NavDropdown` component (Similar to `DropdownButton` but specifically for use within `Nav` components. - `DropdownToggle` Component which can be used as an alternative to the `DropdownButton` `title` prop. Can either be directly imported or used as a static property of the `DropdownButton` with `DropdownButton.Toggle`. _(Useful should you want to use glyphicons or custom html within the toggle that's not a simple string.)_ - `SplitToggle` Similar to the `DropdownToggle` but targeted at the `SplitButton`'s toggle. - Generic `Dropdown` component for easy dropdown customization. Changed: - Event handling of all these components to be in line with #419 - Written with ES6 class syntax Removed: - DropdownStateMixin - Everything is using ES6 class syntax so no more mixin usage
0e161f4
to
346501e
Compare
Linting is all fixed and everything is now squashed. |
Well what are we waiting for then? |
DropdownButton, SplitButton, DropdownMenu, MenuItem Rewrite
Yay 🎉 Finally 🚀 |
+1 for sub-components instead of Though, this appears to be somewhat achievable already, e.g.: var title = <span><i className="fa fa-gear"></i> Settings</span>;
var drop = <NavDropdown eventKey={3} title={title}> ... </NavDropdown>; |
Major part of #526
Adds:
NavDropdown
component (Similar toDropdownButton
but specifically for use withinNav
components.DropdownToggle
Component which can be used as an alternative to theDropdownButton
title
prop. Can either be directly imported or used as a static property of theDropdownButton
withDropdownButton.Toggle
. (Useful should you want to use glyphicons or custom html within the toggle that's not a simple string.)SplitToggle
Similar to theDropdownToggle
but targeted at theSplitButton
's toggle.Changed:
Removed:
Work Remaining: (If anyone would like to help here I'd greatly appreciate it)
onSelect
handlers per Change calls to e.preventDefault() to allow onClick and onSelect calls to override #419Potential Problems that may still exist:
Nav
componentonSelect
handler is passed toNavDropdown
the signatures don't match so we will either need to switch overNav
,NavBar
andNavItem
to the new signature or add some kind of temporary adaptor till we can address them. I'm not sure which option will involve the least amount of work.Minor inconveniences to figure out: (Should not prohibit this PR)
I'm hoping that that's everything needed to put a bow tie on this.