-
Notifications
You must be signed in to change notification settings - Fork 17
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(logo-grid): convert to CSS modules #309
Conversation
π¦ Changeset detectedLatest commit: dda8ed9 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
This pull request is being automatically deployed with Vercel (learn more). π Inspect: https://vercel.com/hashicorp/react-components/9NtxC3wRbEUJKTiiaJKjCtuynibN |
238fe43
to
b655294
Compare
@@ -0,0 +1,3 @@ | |||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> |
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.
Have replaced ×
with this icon for design consistency. Adds a bit of weight but felt this was worth it. In the future we'll swap in a Flight icon here instead of using a local .svg
file.
size?: 'small' | 'medium' | 'large' | ||
} | ||
|
||
function LogoGrid({ |
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've converted to Typescript, and have done a pretty significant refactor, largely due to the switch from Tippy to ReachUI.
[s.removeBorders]: removeBorders, | ||
})} | ||
> | ||
{hasLink ? ( |
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.
Not super proud of this nested ternary, but it felt like a decent way to avoid prop-drilling. Very open to other ideas on how to clean this up π
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.
Only idea I have would be to make it a separate function component, then you could use normal if/else statements. But this doesn't really feel that bad honestly.
) | ||
} | ||
|
||
function CompanyLogo({ company, color, size }) { |
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.
Split this component out, similar to in the previous implementation.
theme?: 'light' | 'dark' | ||
} | ||
|
||
function DialogTooltip({ |
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.
Similar to the Reach-based tooltip
created for tabs
, I split this out in the hopes that it might someday see re-use. I did not try to consolidate with the tabs
tooltip - in this case, we have interactive content in our tooltip, so we need to use a more Dialog-like component.
/* Odd fix for possible issue with useRect, where | ||
tooltipRect did not seem to be set as expected. | ||
I think this works because it forces a re-render | ||
when "shown" changes, which is exactly when we need | ||
to look at the tooltipRef again and re-measure. | ||
Without this, tooltipRect seems to always be null. | ||
Not actually sure why this works. Need to investigate. */ | ||
useEffect(setNow, [shown]) |
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 need help understanding this π
It feels like useRect
should just work without this, and update properly with the dialog's DOMRect
when it is opened (and therefore rendered). I'm not sure why it doesn't. Possibly related to Portal
use, as I did test the same thing without Portal
and it worked fine. cc @BRKalow @jescalan @thiskevinwang in case y'all have any insight π
/* We don't want scroll lock, as this is more of a tooltip than a dialog. | ||
Due to our tooltip-like positioning, when scroll lock is enabled, the | ||
tooltip can become locked in an offscreen position. */ | ||
dangerouslyBypassScrollLock={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.
On the fence about this. Basically the default & recommended "dialog" behaviour is that scrolling becomes locked when the dialog is visible. In our case thought, I think this is kind of bad - since we're positioning the dialog in a tooltip-like way, it's very possible the dialog will be at least slightly out-of-view and will require scrolling to get to.
An alternate solution I thought of might be to try to auto-scroll the page before we set shown
to true, such that the dialog would be ~ centred in the screen. However this seemed like a decent lift, and likely to cause headaches (eg how would we measure the dialog's DOMRect before shown
is set?).
I am curious if anyone has any insights on the implications of this disabling. I read through the Reach docs on this topic. Unlike the dangerouslyBypassFocusLock
prop, where the downsides seem more clear to me (ie, as a screen reader user it seems like lack of focus lock would really mess things up), I'm unclear on the exact downsides of setting this to false
(at least in our use case).
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.
agreed and this seems ok to me in this instance
@@ -16,7 +16,6 @@ | |||
@import '../packages/toggle/style.css'; | |||
@import '../packages/text-input/style.css'; | |||
@import '../packages/hero/style.css'; | |||
@import '../packages/logo-grid/style.css'; |
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 never gets old for me, be forewarned I will probably post these comments in every one of my CSS modules PR self-reviews π€£
integrationLink, | ||
removeBorders, | ||
size = 'small', | ||
className, |
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've added a className
prop. Rationale here is that a quick SourceGraph search can easily determine whether the old global className was targeted in "overrides" - if so, I immediately add a className
prop so that we can, for now, retain these overrides rather than having their replacement block rollout of these components.
In cases where there are no overrides, ie that SourceGraph search comes up empty, I could still see a case for adding a className
prop to enable "safe overrides" (as detailed in the Notion doc on CSS). So if I ever find a component that has 0 overrides in the wild, may still be worth adding 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.
Fantastic documentation, as usual! Left a note about exploring @reach/popover
, which I think might be more appropriate for this pattern.
@@ -0,0 +1,195 @@ | |||
import React, { useState, useRef, useEffect } from 'react' | |||
import { DialogOverlay, DialogContent } from '@reach/dialog' |
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 mean to throw a wrench in your progress here, but do you think https://www.npmjs.com/package/@reach/popover would be more appropriate for this use case?
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 one doesn't appear on their website π€
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, not sure why that is exactly. I do think it's the right component for this use though. It looks like they use it as part of their combobox component.
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.
Ah nice - yeah support for the position
prop could definitely help clean things up a little and make this feel a little less like a re-implementation of Tippy. Hopefully it'll resolve the annoying useRect
issue I was running into as well. Will give it a shot π
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.
@BRKalow I gave @reach/popover
a shot - did up needing some workarounds, but now have both DialogTooltip
and PopoverTooltip
with identical APIs which we can choose from. A quick summary:
-
DialogTooltip
uses@reach/dialog
, which is well-documented, and aligns somewhat with reach.tech's recommendation to usedialog
for "interactive tooltips". By usingdialog
, we get focus behaviour, keyboard and on-click-outside functionality to dismiss the dialog by default. But, the implementation required significant workarounds, including custom positioning, and a weird effect to force re-rendering whenever the dialog is opened or closed. -
PopoverTooltip
uses@reach/popover
. It seems to have no official documentation - unclear why this is. By usingpopover
, we get focus behaviour and custom positioning by default. But, the implementation required the use ofonClickOutside
andonFocusOutside
to allow the popover to be dismissed as expected when a visitor clicks or focuses away.
Leaning towards using @reach/popover
as you recommended, wanted to run this by just in case. If that sounds good, will just commit the deletion of the dialog
-based implementation and this should be good to go π π
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.
Thanks for spiking this out. The popover implementation seems potentially cleaner...what do you think? It seems better to have to handle the click/focus outside than the custom positioning. I'll let you make the final call here though!
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.
+1 I think popover
is a bit cleaner - will go with that unless @jescalan has any strong objections π
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 curious about the popover element bryce mentioned - this is GOOD, as expected, but just feels like a lot of manual implementation
- π¨ Accessibility improvements | ||
- grid items with dialog tooltips now render as focus-able `button` elements | ||
- tooltip a11y is now improved, with features such as focus lock and auto-focusing of the close button when the dialog is opened, thanks to ReachUI | ||
- π¨ Converts to Typescript |
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.
π
[s.removeBorders]: removeBorders, | ||
})} | ||
> | ||
{hasLink ? ( |
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.
Only idea I have would be to make it a separate function component, then you could use normal if/else statements. But this doesn't really feel that bad honestly.
@@ -0,0 +1,195 @@ | |||
import React, { useState, useRef, useEffect } from 'react' | |||
import { DialogOverlay, DialogContent } from '@reach/dialog' |
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 one doesn't appear on their website π€
/* We don't want scroll lock, as this is more of a tooltip than a dialog. | ||
Due to our tooltip-like positioning, when scroll lock is enabled, the | ||
tooltip can become locked in an offscreen position. */ | ||
dangerouslyBypassScrollLock={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.
agreed and this seems ok to me in this instance
/> | ||
</Portal> | ||
) | ||
} |
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.
My only thoughts here are that this is a lot of complicated custom code - I'm not sure that its avoidable, it almost feels like we removed tippy only to effectively re-implement it manually
Co-authored-by: Bryce Kalow <bkalow@hashicorp.com>
Co-authored-by: Jeff Escalante <jescalan@users.noreply.github.com>
9d79270
to
1931fce
Compare
@BRKalow @jescalan Last CSS modules component conversion to merge π Have switched in |
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.
Happy with Dialog or Popover, though the popover implementation seems a little cleaner 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'm good with whichever option you both prefer, which sounds like popover. A little uncomfortable with the amount of custom code involved with both, but it's probably better than tippy, right?
@jescalan Yep, I think it's still more lightweight than Tippy. The "tooltip arrow" part feels like a decent amount of custom code here... I expect if we continue to see tooltip patterns in design (which seems very likely) we can refine things further, and hopefully make the custom parts feel a little more contained π |
ποΈ Asana Task
π Preview Link
This PR converts
@hashicorp/react-logo-grid
to CSS modules. One significant change to enable this shift was the removal of Tippy.js, which has been replaced by a ReachUI Dialog element.PR Checklist π
Items in this checklist may not may not apply to your PR, but please consider each item carefully.