-
Notifications
You must be signed in to change notification settings - Fork 2
Conversation
This adds a component for grouping Buttons together. It simply adds the correct borderRadius to any of it's children that are buttons and passes through the rest of the props. Along with this, the group can be disabled rather than having to disable all buttons individually.
> | ||
{React.Children.map(children, child => { | ||
if (child.type !== Button) { | ||
return child; |
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 did this because, in my use case, I wanted to put a hidden input inside of the ButtonGroup without it becoming a Button. I figured this was fine and it would be better not to screw with children that aren't buttons but maybe I'm wrong on that.
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 initially against this approach but after thinking about it for a little bit I think this is probably the right way to go. It'll prevent the ButtonGroup
component from breaking if it's passed components that aren't Button
s 👍
/** Callback when mouse enters component. */ | ||
onMouseEnter: PropTypes.func, | ||
/** Callback when mouse leaves component. */ | ||
onMouseLeave: PropTypes.func, |
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.
children
needs to go here too, this broke CI
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 seems a bit odd to me because children
is a prop on every component. There's discussion here on whether this should be enforced jsx-eslint/eslint-plugin-react#7 but I ended up adding it because it's not too difficult.
className: '', | ||
disabled: false, | ||
onMouseEnter: () => {}, | ||
onMouseLeave: () => {}, |
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.
children
needs a default prop too
<GroupedButton | ||
disabled={disabled} | ||
{...child.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.
could this fit in 80 chars? <GroupedButton disabled={disabled} {...child.props} />
CI complains here.
dev_block 🌮 merge conflicts but CR 👍 progress looks good |
There are still CI failures. Hopefully this actually fixes them.
Codecov Report
@@ Coverage Diff @@
## master #33 +/- ##
===========================================
+ Coverage 19.71% 43.94% +24.23%
===========================================
Files 14 16 +2
Lines 142 157 +15
Branches 11 14 +3
===========================================
+ Hits 28 69 +41
+ Misses 114 88 -26
Continue to review full report at Codecov.
|
This adds new tests for the ButtonGroup with snapshots. It also pushes the latest version of the toolbox distribution since that got borked during merging.
good to un block? |
Yep. un_dev_block 💥 |
CR 👍 |
|
||
ButtonGroup.propTypes = { | ||
/** Buttons to be grouped together. */ | ||
children: PropTypes.arrayOf(PropTypes.node), |
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 find that PropTypes
read much nicer when you destructure the types in the import:
import { arrayOf, node } from 'prop-types';
...
ButtonGroup.propTypes = {
children: arrayOf(node),
...
}
<ButtonGroupContainer | ||
className={className} | ||
onMouseEnter={onMouseEnter} | ||
onMouseLeave={onMouseLeave} |
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 need to explicitly pass onMouseEnter
and onMouseLeave
to the ButtonGroupContainer
? I think a better approach might be to collect the unused props and spread them onto the container. Like this:
const ButtonGroup = ({ children, disabled, ...props }) => (
<Div display="inline-block" {...props}>
...
</Div>
);
Notice that I used Div
instead of ButtonGroupContainer
. Since ButtonGroupContainer
only contains the display: inline-block
rule, this is a good place to use glamorous' Div
component and simply pass a display
prop instead of defining a new component. From the glamorous docs:
Having to name all of that stuff could be tedious, so having these pre-built components is handy. The other handy bit here is that the props are the styles of these components.
I like to use the built-in components for layout purposes like setting display
or position
.
> | ||
{React.Children.map(children, child => { | ||
if (child.type !== Button) { | ||
return child; |
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 initially against this approach but after thinking about it for a little bit I think this is probably the right way to go. It'll prevent the ButtonGroup
component from breaking if it's passed components that aren't Button
s 👍
display: 'inline-block', | ||
}); | ||
|
||
const GroupedButton = glamorous(Button)({ |
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 ButtonGroupItem
would probably be a better name here.
|
||
'&:first-of-type': { | ||
borderTopLeftRadius: borderRadius, | ||
borderBottomLeftRadius: borderRadius, |
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 should probably handle border-width
as well. We can do this by setting the border-right-width
to 0
for all ButtonGroupItem
s except the last one (which would have a border-right-width
of 1
.
) | ||
.toJSON(); | ||
expect(tree).toMatchSnapshot(); | ||
}); |
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 should probably add a test for when ButtonGroup
wraps a component other than Button
.
}; | ||
|
||
ButtonGroup.defaultProps = { | ||
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.
Does it make sense to have an empty ButtonGroup
? I'm cool with making children
a required prop.
@@ -7,6 +7,7 @@ import './plugins'; | |||
export { default as glamorous } from 'glamorous'; | |||
|
|||
export { default as Button } from './components/Button/Button'; | |||
export { default as ButtonGroup } from './components/ButtonGroup/ButtonGroup'; |
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.
Nice 👍 I always forget to export components from Toolbox.
Nice work! Thanks for bearing with me as Toolbox changes :) I know the commit message convention can be annoying (I'm not a huge fan either) but I promise that the benefits of formalized commit messages outweigh the annoyances. You can read more about that here: https://github.com/iFixit/toolbox#why If you have any other feedback about how we can improve Toolbox, I'd love to hear it. deploy_block 👍 on responding to my comments. |
CR ⚡ I've read to here but it's still blocked on some changes |
Tested out the different props/methods on the example code for the ButtonGroup and its four children Buttons. The only one that didn't seem to have any effect was dev_block ☀️ |
The issue was that the disabled prop was being overridden by the more generic {...child.props}. To fix this I just had to reorder the props. Along with this I made several style changes suggested in CR.
This fixes the issue of having both the borderLeft of one button and the borderRight of the other button creating a border with twice the normal width. Instead, we remove the borderRight for all but the last button and use only the borderLefts to separate buttons.
This adds the test case for when a ButtonGroup has other children besides Button components. It should, in this case, not alter the other children as the updated shapshots show.
Addressed all the comments with the last few commits. un_deploy_block 💥 un_dev_block 💥 |
|
||
const { borderRadius } = constants; | ||
const { Div } = glamorous; | ||
|
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 could include this in the import above. It would just be:
import glamorous, { Div } from 'glamorous';
const ButtonGroup = ({ children, disabled, ...props }) => ( | ||
<Div display="inline-block" {...props}> | ||
{React.Children.map(children, child => { | ||
if (child.type !== Button) { |
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 a little bit confused why this is necessary. Is there really a good reason to ever wrap something that isn't a Button
in a ButtonGroup
?
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.
In my use case I have a hidden input inside the ButtonGroup so there's one.
</ButtonGroup>, | ||
) | ||
.toJSON(); | ||
|
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 super minor, but I'd probably remove this extra line. Just to be consistent with how it is above.
return child; | ||
} | ||
return <ButtonGroupItem {...child.props} disabled={disabled} />; | ||
})} |
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.
Doesn't this mean that you can only ever disable the entire button group? What if we want to disable just a single button in the group?
I think you could do something like:
return <ButtonGroupItem {...child.props} disabled={disabled || child.props.disabled} />;
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 catch I'll fix that right away.
I've read up to here now, but there are still some outstanding questions |
The fact that the ButtonGroup's disabled overrode the childrens meant that you couldn't individually disable the children. This updates it so you still can and adds a test case to verify it works.
This removes the unnecessary additional line for destructuring glamorous to get Div.
Okay I think I've addressed everything. Another round! |
Thanks for making those changes! |
CR ⚡ |
QA ☀️
|
This adds a component for grouping Buttons together. It simply adds the
correct borderRadius to any of it's children that are buttons and passes
through the rest of the props. Along with this, the group can be
disabled rather than having to disable all buttons individually.
On Deploy
Choose "Squash and merge" instead of "Create a merge commit". Then, in the title field write:
"feat: Add
ButtonGroup
component".This is so the commit messages don't end up cluttering the release notes.