-
Notifications
You must be signed in to change notification settings - Fork 32
feat(GlobalHeader): add getGlobalHeaderHeight helper function #1417
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
Conversation
Codecov Report
@@ Coverage Diff @@
## main #1417 +/- ##
==========================================
+ Coverage 82.23% 82.28% +0.04%
==========================================
Files 316 318 +2
Lines 2545 2552 +7
Branches 663 663
==========================================
+ Hits 2093 2100 +7
Misses 399 399
Partials 53 53
|
|
this is still a draft, final version will have unit tests if this looks like a reasonable add |
| // For performance reasons, this component renders the mobile and desktop versions | ||
| // of itself simultaneously and switches between them using css (instead of using | ||
| // any of the useBreakpoint hooks, which rely on js for the same behavior). |
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.
🎉
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.
LGTM. Thanks Chris for taking the time to work out and comminucate re: the best solution.
It was discussed in this thread:
https://github.com/Codecademy/client-modules/pull/1417/files#r577980940
I too am curious about the performance impact useBreakpointAtOrAbove does have vs rendering both versions and using css to toggle.
If the overhead is unnecessary given the need, I wonder if we should audit and look into just replacing current use of useBreakpointAtOrAbove (and marking as deprecated) across the monolith/static-sites and replace it with CSS. I think in most cases, it's just for this mobile v desktop view need on a single component.
JoshuaKGoldberg
left a comment
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.
Err, what about react-anchor-link-smooth-scroll? Can you show an example in the monolith of needing this JS hook?
|
@rogervera yeah that was my original concern with the hooks and why I was so dubious about their need 😄 . https://codecademy.atlassian.net/browse/TR2-394 -> https://codecademy.atlassian.net/browse/REACH-475 Conclusion: most of the time, these hooks are not a good idea to use in components that are visible on page load. |
|
@JoshuaKGoldberg not the monolith, but static sites: would help us get rid of the hardcoded |
| <Box display={{ base: 'none', md: 'block' }} height="80"> | ||
| <Box | ||
| display={{ base: 'none', [breakpoint]: 'block' }} | ||
| height={desktopHeight.toString()} |
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.
@codecaaron I wonder if we could expand the types for height and width to allow number | string, so folks didn't have to manually toString()?
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! It technically will already handle numbers with no units cleanly so it should just be a matter of updating the default types
| 2. Update `GlobalHeaderVariants.tsx` to include the new item for the user roles that need it. | ||
| 3. Update tests in `GlobalHeader-test.tsx`. | ||
|
|
||
| ### How to Access GlobalHeader's height |
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.
@christian-dinh about the resize situation: are there situations other than scrolling to a specific element that would care about the header height? I wonder if we could avoid the fragile number variables by using a ref after all, but exposing a scrollPastHeader function as part of a React Context instead of a hook...
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.
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's also possible that we would want to forego this pathway entirely in favor of css variables if we only want this information for CSS rules.
Like, we can include a base sass file with something like:
:root {
--global-header-height: 64px;
}
@media screen and (max-width: 800) { // or whatever our mobile breakpoint is {
:root {
--global-header-height: 80px;
}
}
And then we don't expect our components to receive this information through React (JS) at all. We just update their sass stylings to use these variables directly.
If we only want these values for css purposes, then I think this accomplishes the best of both worlds (aka, The Hannah Montana Solution), where we never have the flash of incorrect styling because SSR doesn't have a width value. It's always rendered correctly on the first pass from CSS.
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.
that's a pretty strong proposal, and actually if we expose a ref on the header we should still be able to access the value in js:
getComputedStyle(headerRef.current).getPropertyValue('--global-header-height');I do think that js visibility is a requirement for header-clearing scroll targets (since scroll-margin-top is not supported in safari), but this feels pretty good to me if it works.
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.
or yeah put it on :root and then we don't need a ref
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.
Gotcha, I get it now (and learned about emotion globals!). Thanks for the explanation!
Would a snapshot of <GlobalHeader />'s <Global /> not be sufficient to confirm that it's providing the values we're looking for? Like, we don't usually test to confirm that CSS is being applied in the way we expect it to, do we? Would a cypress test be helpful if we really want to confirm that they're being applied correctly?
And for the helper, that should be testable, right?
I'm generally inclined to keep these variables at the :root level (for ease of access in css) over using a ref, especially since it seems like we're going to be looking to use this in JS in non-react-ive patterns (imperatively, as you pointed out).
I think what you've got here is especially awesome already. Excited to have this kind of flexibility in our repo!
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.
Totally fine with keeping it at :root for the reasons you mentioned. I was actually specifically having trouble testing the helper, but I think I might have just had a Big Brain Moment™ 🤯 stand by
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.
ok I switched up what the test was testing and I think this feels pretty good now. Still need to update docs but lmk what u think.
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.
Sorry my computer has been out of commission since the weekend. Finally caught up on setting up new on.
I'll take a look at these comments tonight.
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.
@christian-dinh Thank you for all of this! Not only do I think this is some awesome code, but I've loved the conversation about it.
I left only a single nit/question, otherwise, to whatever extent my approval matters, I think this is some Grade A code right here.
packages/styleguide/stories/Labs/Experimental/Molecules/GlobalHeader.stories.mdx
Show resolved
Hide resolved
JoshuaKGoldberg
left a comment
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 CSS variable discussion is interesting, but I don't have any other ideas so approving anyway 😄
📬Published Alpha Packages:@codecademy/gamut-labs@10.1.1-alpha.468fb4.0 |
|
🚀 Styleguide deploy preview ready! |
|
|
||
| export function getGlobalHeaderHeight(): number { | ||
| return parseInt( | ||
| getComputedStyle(document.documentElement).getPropertyValue( |
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.
nit: Does this need the optional chaining on document to work on SSR? Or does it fail gracefully as-is? I dunno myself, just wondering!
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.
document won't exist in SSR in the monolith anymore. So we'll want to put this on a preview server for sure. 😄
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.
given the use case I don't see when this function would be called during SSR, though if it is would it be helpful to log a console warning?
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 I like it as -- it should aggressively crash if used in a component's initial render, as a way to tell us to not do that thing 😄
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.
That's a great idea, yea!
|
closing cause https://github.com/Codecademy/client-modules/pull/1444 does all this and more 🎉 |
Overview
There are two different ways I tried to do this, both visible in two commits. the first (with refs) is fancier but probably unnecessarily so. It uses refs andresizelisteners inside ofuseLayoutEffectto function agnostically from how the header is sized. The second (without refs) simply sets the height based onuseBreakpointAtOrAboveand uses it for both the imperative handle and the sizing of the header itself. Both useuseImperativeHandle, but the latter way seems better to me so that's what the main diff is. If you look at the first commit on its own and prefer it I am open to discussion! Also open to alternatives to an imperative handle if anyone has a better idea.Adds a
hookhelper function for getting the current height of theGlobalHeaderfor layouts that require that info. Includes docs and unit tests!PR Checklist