-
Notifications
You must be signed in to change notification settings - Fork 371
feat(button): add favorite variant #11853
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(button): add favorite variant #11853
Conversation
Preview: https://patternfly-react-pr-11853.surge.sh A11y report: https://patternfly-react-pr-11853-a11y.surge.sh |
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 some initial comments below, the animation works nicely so far ⭐
We should also add a console warning if isFavorite && !ariaLabel
stating that each favorite button must have a unique aria-label that indicates the current favorited state
packages/react-core/src/components/Button/examples/ButtonFavorite.tsx
Outdated
Show resolved
Hide resolved
@srambach @andrew-ronaldson just FYI, the no-padding variant is visually broken. If you go to the favorite button example from this PR and add |
Hmm yes, looks like we're setting the icon color for a plain no-padding button and that's overriding the favorited color. https://github.com/patternfly/patternfly/blob/d375e1dc0f924f11149fe105875caedbcefd1705/src/patternfly/components/Button/button.scss#L617 |
|
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.
Lengthy comment below.
We should also add some unit tests for the new props/classes being applied.
isFavorite | ||
isFavorited={isFavorited} | ||
onClick={toggleFavorite} | ||
icon={<StarIcon />} |
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 addition to Andrew's comment above about using the outlined star icon when the button isn't favorited, we should apply the icons internal to the Button component when it's a favorite button since we also need to wrap these star icons in additional class wrappers and both icons should be rendered in the DOM at the same time (rather than dynamically rendering the correct icon, as these additional class wrappers will determine which one is hidden or not).
Here's the Core markup for the icons:
vs the markup in the PR preview:
Though @andrew-ronaldson would we want to allow a consumer to customize the favorite icon(s) at all? If we always have both icons rendered we'd most likely need to add some other props (favoriteIcon
and favoritedIcon
or something) since we need to place the correct icons in the correct icon wrapper. Dynamically rendering the correct star icon might be a little cleaner, since then you only need to pass in the existing icon
prop, and the animation still seems to work, but it makes some of the Core styling unused in React/creates a mismatch in markup between Core and React.
Figure I'd ask this now because depending on the answer (and the approach if the answer is "yes"), might be less of a headache to deal with it now than try to finagle something without causing a breaking change to the markup later.
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 need to allow for their own custom favorite icon. Side note, Would it be better if it was one icon with a stroke and a fill that gets set by a class? the hamburger icon is unique and we play with paths so thought i'd ask.
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 go into it with the stance that we don't want consumers to be able to customize the "favorites" icon, I think the current implementation (2 icons that need their own distinct wrappers) isn't too bad. 1 icon that just gets a class applied to handle the filling of the icon would be less to deal with, but I don't think it's absolutely needed, especially since - even though it would probably be a quick Core update - it's still time being taken away from any remaining animations work we need to get done.
### Favorite | ||
|
||
You can pass both the `isFavorite` and `variant="plain"` properties into the `<Button>` to create a favorite button. Passing the `isFavorited` property will determine the current favorited state and update styling accordingly. |
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.
@edonehoo can you give this a quick review?
27c1ba7
to
46fddb2
Compare
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 a couple comments that need design input below cc @andrew-ronaldson @kaylachumley , but this is continuing to shape up awesomely
isFavorite && variant === ButtonVariant.plain && styles.modifiers.favorite, | ||
isFavorite && isFavorited && variant === ButtonVariant.plain && styles.modifiers.favorited, |
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 would need design input, but rather than needing the consumer to explicitly pass the plain variant in, we could force the plain button styling when isFavorite is true.
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.
Per conversation from an animation sync today, we want to not restrict the variant for these buttons. Our design guidelines will recommend when to use what variants for these. So we can remove the && variant === ButtonVariant.plain
from these 2 conditionals (but keep the example so that we're passing variant="plain"
)
}; | ||
|
||
const _icon = renderIcon(); | ||
const _children = children && <span className={css('pf-v6-c-button__text')}>{children}</span>; |
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.
Also design input needed, but if intend to not allow text content for a favorite button, we could add a && !isFavorite
check here.
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.
Disregard this comment, we don't want to restrict the rendering of children for these buttons
Looks 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.
Looks good to me. Animation is very cute!
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 addition to the below comments, let's add another test that checks that the icon
prop is overridden when isFavorite is passed in.
test('Renders favorite icon with class pf-m-favorite when isFavorited = false', () => { | ||
render(<Button isFavorite />); | ||
expect(screen.getByRole('button')).toHaveClass('pf-m-favorite'); | ||
}); |
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.
For this test, let's use the imported styles object rather than hardcoding the class names to expect. So we can replace pf-m-favorite
with styles.modifiers.favorite
(or whatever the modifier property is, I assume it'd be favorite though) both in the test name and the toHaveClass call
Additionally, let's update the test name to reflect more what that test is expecting: "Renders with class [classname here] when isFavorite is true".
And then last thing is we should include a test that checks this class isn't applied by default/when isFavorite is false.
test('Renders favorite icon with class pf-m-favorite when isFavorited = true', () => { | ||
render(<Button isFavorite isFavorited />); | ||
expect(screen.getByRole('button')).toHaveClass('pf-m-favorited'); | ||
}); |
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 updates here as the above test: using the styles object, updating the test name, and including a test that check the pf-m-favorited class isn't applied by default
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're a ⭐
af39a79
to
d3f6e65
Compare
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.
Awesome work! 🤩 You could say this is my pf-m-favorite
Your changes have been released in:
Thanks for your contribution! 🎉 |
Closes #11809