Hidden material UI still rendering element - reactjs

I am trying to conditionally hide a material ui component.
My first thought was that I'd simply not render the element at all (given I'm not purely hiding it due to 'breakpoint' reasons)... but according to the documentation for the mateiral UI Hidden element here: https://material-ui.com/layout/hidden/
This has the benefit of not rendering any content at all unless the
breakpoint is met.
Score, that sounds great. I could say the Hidden element applied when larger than xs and smaller than lg and it'd have the effect of always hiding the component when applied.
However, when I wrap a component in a hidden element using this code:
let withPaper = <Paper>{this.buildQuestion()}</Paper>;
let withToolTip = withPaper;
if (tooltip != null) {
withToolTip = <Tooltip title={tooltip} enterDelay={500} leaveDelay={200}>{withPaper}</Tooltip>
}
let withHidden = withToolTip;
if (this.props.hidden) {
withHidden = <Hidden xsUp xlDown>{withToolTip}</Hidden>
}
return withHidden;
only the visibility appears to change. It still takes up space on the screen. Look at the following two screenshots. You will notice that the "Station Number" text field shows up when the Hidden is not included and it's invisible when it is included... however, the component is still taking up space in the material-ui Grid.
(ignore the messed up vertical alignment)
Without the Hidden component on the station number:
With the Hidden component:
Based on the documentation, this doesn't appear to be the normal/correct behavior.
How can I get the wrapped component to completely not impact anything on the screen (hopefully while still being able to access it's values and props?)?

Turns out my component was sitting in a grid item (https://material-ui.com/layout/grid/) so, while the Text Field wasn't actually rendering... an empty grid items was.

Related

Storybook and Tailwind dark-mode works in Document view but not in Canvas view

After setting up the storybook-tailwind-dark-mode add-on for Storybook (by following these steps), my component is no longer displaying correctly in dark-mode in the Canvas view. The component displays correctly while in Document view and other components are displaying correctly in canvas view, so not every component has this issue.
The elements are visible for a split second before the page goes blank. When inspecting the page, I can see all of the elements are there, but they are just not visible.
The only difference to the HTML seems to be the dark class added to the body element.
Any ideas as to why the elements are no longer displayed would be greatly appreciated ⚡️
I've inspected the elements to see what could be causing the elements to not be displayed. I was expecting to see a change to display:none or an element that is in front of the other elements, causing them to be hidden, but it seems the only change is the dark class being added to body.
I've also looked at ./storybook/preview.js and ./storybook/main.js for anything suspicious but I haven't found anything that looks out of place.
There was a modal <div> that had a dark:bg-gray-800 class that was being overlayed over all of the other elements.
The modal was correctly set in light mode to show and hide according to when the modal was open/closed, but this conditional was not applied for dark mode, so the modal was always open, and hiding the other elements.

Component using "Suspense" showing spinner on consequent loads (changing its height for a moment)

I'm rendering a number of items, where each individual item uses the same component:
This component internally uses Suspense:
<Suspense fallback={<Spinner />}>{children}</Suspense>
Whenever I click the paginator, a new set of items is rendered. Each of the items uses the same "Suspensed" component.
Problem: Each of the instances shows a fallback (spinner, loader) for a moment, and only then its content.
Since the fallback has constant height, this changes the height of the parent container, which makes the whole page jumping around:
I'm wondering how could I fix this? Basically, I'd like to avoid the new set of items to collapse due to showing the fallback. Sure, showing the fallback on initial load is fine, but I don't think the already loaded component (dynamically imported code) should show it on consequent pages.
I tried using React.startTransition, but that didn't help.
I also checked with components which are not lazily loaded, and everything works fine (parent height remains constant).
Thanks for help!
Update: I came up with a "poor man's fix":
wrapping children inside 2 divs
ResizeObserver monitoring the height of the inner div and setting the same height to the outer one, but in debounced fashion (100ms later)
Resources:
https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver/ResizeObserver
https://www.npmjs.com/package/use-debounce
Note: You'll probably need to mock ResizeObserver in your Jest tests: https://github.com/que-etc/resize-observer-polyfill/issues/50#issuecomment-488064120

How to trigger an event when an element intersects another element?

I am stuck on implementing a UI in React.
I want to trigger a state change when an element crosses the centre of the viewport.
Here's a prototype of the design: https://cln.sh/sNhueq
In this prototype, the box on the right is sticky so it stays on the screen. And the list on the left moves as we scroll. I want to know when a list item crosses that red line so I can change the content of the box.
I am using framer-motion and react-intersection-observer.
Here's what I tried:
I tried using the viewport prop of <motion.div> but it triggers when the element enters the whole viewport. Yes, we can set root prop to an element's ref but for that the root element has to be an ancestor which the red line is not.
I tried react-intersection-observer but got the same results (because the ancestor limitation comes from the IntersectionObserver API in general).
I ultimately thought of some hacky non-performant ways like having a scroll listener, checking the bounds of root and target and finding if they collide. But I really don't want to do that heavy computing.
Is there any way with IntersectionObserver or something else that is performant?
Any help is appreciated. Thank you! :)

How to conditionally display items on top when no room below with react-select 2

Using react-select 2, I'm trying to figure out the best way to display the opening direction, depending where on the page (and in the viewport) the select element is.
I've considered using the onMenuOpen prop to check how much space is below the select component and then add a class name when required - and handle the positioning in CSS, but I'm worried that could end up in an infinite loop.
The menuPlacement prop on its own won't work, as that will control the direction for all times, not when the component is near the bottom of the viewport (or conversely near the top of the viewport).
Does anyone know what I could do?

How can I scroll to to the top of a "simple" react-list when it's redisplayed?

I'm using react-list to display lists data within Material-UI Tab components.
I'm using the simple type in the list, e.g.
<ReactList itemRenderer={::this.renderItem}
length={this.props.contacts.length}
pageSize={20}
type="simple"
useTranslate3d={true} />
I have to use simple as I don't know the size of the rendered items.
This means I can't use scrollTo fully. From the docs
Note that if you aren't using type='uniform' or an itemSizeGetter, you will only be able to scroll to an element that has already been rendered.
When I'm work with the list on one tab and scrolled, say, half way down, when I switch to another tab, I'm scrolled some way down the list that has been updated with the new data.
What I'd like is to have the react-list reset to display the first item when I switch tabs.
I've tried putting a ref in ReactList component and then calling scrollTo---like this
ref={c => this.list = c}
componentDidUpdate() {
this.list.scrollTo(0, 0);
}
Had no effect.

Resources