-
Notifications
You must be signed in to change notification settings - Fork 198
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
Update AdderToolbar components and styling #4753
Conversation
This gets us the correct AnnotateIcon
// its SVG dimensions dictate | ||
'h-auto w-auto z-2', | ||
'text-grey-3 fill-white', | ||
<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.
Here's an example of me adding an additional parent component to handle the positioning, and not applying that styling directly to the icon component. This is less of a real concern with icons, which have no classes applied to them other than what you set on className
, but it's more hygienic IMHO.
<ButtonBase | ||
classes={classnames( | ||
'flex-col gap-y-1 py-2.5 px-2', | ||
'text-annotator-sm leading-none', | ||
// Default color when the toolbar is not hovered | ||
'text-grey-7', | ||
// When the parent .group element is hovered (but this element itself is | ||
// not), dim this button's text. This has the effect of dimming inactive | ||
// buttons. | ||
'group-hover:text-grey-5', | ||
// When the parent .group element is hovered AND this element is | ||
// hovered, this is the "active" button. Intensify the text color, which | ||
// will also darken any descendant Icon | ||
'hover:group-hover:text-grey-9', | ||
// Set the .hover-group class for use by `NumberIcon` | ||
'hover-group' |
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 use case is a good example of both the pros and cons of ButtonBase
. On the "pros" side, we automatically get consistent transitions and focus rings and whatnot, so those don't have to be managed manually, nor risk being inconsistent. On the other hand, I just kind of have to "know" that ButtonBase
already sets a flex
layout, so I just need to set flex-col
to go columnar. But I can feel assured that padding and colors won't conflict, as the coalescing convention for base classes is never to style dimensions or colors...
)} | ||
onClick={onClick} | ||
title={title} | ||
> | ||
{icon && <Icon classes="text-annotator-lg" name={icon} title={title} />} | ||
{Icon && <Icon className="text-annotator-lg" title={title} />} |
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.
At least className
gives a hint that your classes are the only classes...
dir="ltr" | ||
style={{ | ||
visibility: isVisible ? 'visible' : 'hidden', | ||
}} | ||
> | ||
<div className="flex dim-items-on-hover"> | ||
<div className="flex group"> |
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 wish Tailwind's group
class had a better name. It's so...vague.
tailwind.config.mjs
Outdated
// Custom variant for a specific use case in which an element needs to | ||
// style itself based on the hover states of TWO parents (.group and | ||
// .hover-group). See `src/annotator/components/AdderToolbar` | ||
addVariant('hover-group-hover', '.group:hover .hover-group:hover &'); |
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 not gonna mince words: this is a tad fugly. I hope the comments everywhere help. I've just never quite run into a situation like this before, where the hover state of two ancestors has to be assessed.
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.
A few searches online finds that plenty of folks have found use cases for nested groups, similar to what we have here. It doesn't seem that unusual to me. The basic solutions I've seen boil down to adding variants to create additional groups that are named by semantic function or level.
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.
Regarding NumberIcon
colors, it looks to me like this particular use case can be solved without needing to deal with nested groups using currentcolor
. The need for styling which depends on the states of multiple ancestors doesn't seem that unusual to me (eg. see Tailwind feature request I linked in the comments), and I think it is something we should be able to accomplish without needing a ton of documentation each time. A high-level description of what the user should see is always useful. The solutions I can think of / find online boil down to one of:
- Adding some support for labeled groups, with varying degrees of generality, which is basically what you did here. If we're doing this, I'd suggest giving the groups names that reflect their semantic role or level in the hierarchy.
- Setting CSS variables at the top of the group, which children can then consume. This allows the ancestors to set the context ("the current foreground color is $X") while individual components encapsulate how it is applied ("set the
color
property to $X").currentcolor
is a special case of this.
Other than NumberIcon
, I suggested we stick with with icon
as the prop name to match the pattern library, but continue to accept components as values.
The rest of the changes look good to me.
); | ||
} | ||
|
||
/** | ||
* @param {object} props | ||
* @param {number} [props.badgeCount] | ||
* @param {string} [props.icon] | ||
* @param {IconComponent} [props.Icon] |
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 settled on continuing to use the lower-case icon
for the prop name in the frontend-shared package. I think we should do the same here.
// when its parent button is hovered, even if this badge's span is not | ||
// directly hovered. | ||
// This is a custom tailwind variant | ||
'hover-group-hover:bg-grey-9' |
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.
Another way of doing this in plain CSS might be to pass down a custom variable indicating the foreground color. The toolbar would set this to either the unhovered medium gray or dimmed gray depending on its hover state, and the active button could override it. The various elements inside the button would then consume this foreground color variable in different properties (color
, background-color
etc.). I don't know off-hand how easy that is to translate to Tailwind.
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.
currentcolor
could also work here, although we need to introduce a separate element for the background and the text to use the inherited color for the background instead of the inverted color:
function NumberIcon({ badgeCount }) {
return (
<span className="rounded px-1 py-0.5 bg-current">
<span className="text-color-text-inverted font-bold">{badgeCount}</span>
</span>
);
}
'text-color-text-inverted font-bold', | ||
// Default background color when there is no hovering going on | ||
'bg-grey-7', | ||
// When the div.group element is hovered, but the .hover-group |
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 hover-group
naming seems ambiguous to me, since both groups (toolbar and button) are being hovered here. The main distinction is either the relative level of the group (more generic) or the semantic meaning of the group (more specific). If the groups had semantic names (eg. toolbar-group
or group-toolbar
) then you could apply toolbar-group-hover:bg-grey-5
, button-group-hover:bg-grey-9
and it would be a bit more obvious what is going on.
You may have already come across this, but I found some ideas in tailwindlabs/tailwindcss#1192.
@@ -110,6 +136,36 @@ function ToolbarButton({ badgeCount, icon, label, onClick, shortcut }) { | |||
* The toolbar that is displayed above or below selected text in the document, | |||
* providing options to create annotations or highlights. | |||
* | |||
* The toolbar has nuanced styling for hover. The component structure is: |
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.
While this comment is useful, the requirements here don't seem that crazy or weird to me and it is going to be a pain if we need to write this much detail each time. Also there is a risk that the comments get out of date if we revise the implementation to use a simpler method in future.
tailwind.config.mjs
Outdated
// Custom variant for a specific use case in which an element needs to | ||
// style itself based on the hover states of TWO parents (.group and | ||
// .hover-group). See `src/annotator/components/AdderToolbar` | ||
addVariant('hover-group-hover', '.group:hover .hover-group:hover &'); |
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.
A few searches online finds that plenty of folks have found use cases for nested groups, similar to what we have here. It doesn't seem that unusual to me. The basic solutions I've seen boil down to adding variants to create additional groups that are named by semantic function or level.
@robertknight |
* Use updated components and icons * Refactor to eliminate external styles - Add tailwind utility class for `all: initial`
be67125
to
53decc3
Compare
OK, "reboot" here, much simpler, using |
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.
Revised version LGTM
This PR updates the shared components used by
AdderToolbar
, and updates its Tailwind styling to eliminate the need for external CSS. I'm focusing on this component because I expect we'll make some adjustments in this area soon for accessibility reasons.This component has some of the most fiddly styling of any of our components. It was also one of the first I converted to Tailwind. Much has been learned since February, but it doesn't eliminate the reality that the hover behavior for the
AdderToolbar
is rather nuanced.These changes:
frontend-shared
to 5.4.1 to get the correctAnnotateIcon
all: initial
, which is something we do forAdderToolbar
(it's in a shadow DOM) and isn't available in stock TailwindAdderToolbar
's styling