How to hide wrapped components in React - css

I need to be able to hide components that gets wrapped because it goes over the max width.
<div style={{width:100}}>
<div style={{width:50}}>
component1
</div>
<div style={{width:50}}>
component2
</div>
<div style={{width:50}}>
component3
</div>
</div>
//But I actually use map to render children
<div style={{width:100}}>
{components.map((item, index) => {
return <div style={{width:50}}>component{index + 1}</div>)
}}
</div>
as shown in the code above, the parent div is of with 100. So the last component (component3) would go over the width of the parent by 50px and will be rendered in the second line. However, I want any component that leaves the first line to be not rendered at all. How do I make sure that only component1 and component2 shows and excludes component3?

You could add up the widths of all the components in a separate variable, and render null for all components remaining after the total width of those already rendered exceeds 100.
Example
class App extends React.Component {
state = {
components: [{ width: 50 }, { width: 50 }, { width: 50 }]
};
render() {
const { components } = this.state;
let totalWidth = 0;
return (
<div style={{ width: 100 }}>
{components.map((item, index) => {
totalWidth += item.width;
if (totalWidth > 100) {
return null;
}
return (
<div key={index} style={{ width: 50 }}>
component{index + 1}
</div>
);
})}
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>

Related

Keeping two components the same height in all screen sizes (one with scroll, another without)

I have the following use case described in the image below.
I'm using Bootstrap 5 & React with Typescript
There are two components in a page called MainPage.tsx called Component1.tsx and Component2.tsx
Component2 has many more elements/content than Component1, so I want to put a scrollbar into it
I want Component1 to be the same height as Component2
On screen sizes with a width larger than >=768px (Boostrap .md breakpoint) I want the Component2 to be to the right of Component1. On mobile-like screens with widths >=576px (Bootstrap .sm breakpoint), I want Component2 to be right below Component1. In both modes, Component1 maintains its scrollbar.
However, what happens in my current code is that on mobile-like screens (when Component2 is below Component1), there is a big empty space between the two components.
My current code looks like this:
// MainPage Component
const MainPage = () => {
}
return (
<div className='d-flex flex-column flex-lg-row'>
<Component1 />
<Component2 />
</div>
)
}
export { MainPage }
// Component1.tsx
const Component1 = () => {
return (
<div className='flex-column flex-lg-row-auto w-100 w-lg-300px w-xl-400px mb-10 mb-lg-0'
style={{ overflow: 'scroll', overflowX: "hidden", height: "100vh" }}>
<div className='card card-flush'>
<div className='card-header pt-7'>
<OtherComponent1>
</div>
<div className='card-body pt-5'>
<div
className='scroll-y me-n5 pe-5 h-200px h-lg-auto'>
<OtherComponent2> />
</div>
</div>
</div>
</div>
)
}
export { Component1 }
// Component2.tsx
const Component2 = () => {
return (
<div className='flex-lg-row-fluid ms-lg-7 ms-xl-10'>
<div className='card' style={{ height: '100vh', overflowX: "hidden" }}>
<OtherComponent3/>
</div>
</div>
)
}
export { Component2}
However, what happens is that with this code, in boostrap .md screen-sizes it works as intended, but in bootstrap .sm screens-sizes, there's a big empty space between the two components. I suspect the problem is due to the "100vh" in Component1.tsx
What is the culprit and how can I solve it?

Grid Layout for Tweets inside TwitterTimelineEmbed

I'm using react-twitter-embed to display a timeline in a home page. But I would like to add a custom CSS grid (the tweets, limited by six, must appear horizontally and not vertically):
import { useTranslation } from "react-i18next";
import { TwitterTimelineEmbed } from "react-twitter-embed";
import { FollowUsOn } from "../Footer/SubModules/FollowUs/follow-us-on.component";
import { BlockTwitterBtn } from "./SubModules/block-twitter-btn.component";
export const BlockTwitter = () => {
const { t } = useTranslation();
return (
<div className="container blockTwitter">
<div className="blockTwitter__firstCard">
<h3 className="blockTwitter__title">{t("common:blockTwitterTitle")}</h3>
<BlockTwitterBtn />
<FollowUsOn />
</div>
<section className="twitterContainer">
<div className="twitter-embed">
<TwitterTimelineEmbed
sourceType="profile"
screenName="Quebecor"
options={{
tweetLimit: "6",
width: "100%",
height: "100%"
}}
noHeader="true"
noFooter="true"
></TwitterTimelineEmbed>
</div>
</section>
</div>
);
};
I read I could use the option onLoad={function with custom CSS}, but I don't know exactly how to do this on React...

Hide nav button in react-material-ui-carousel

I've just implemented the react material ui carousel, and it was pretty straightforward, the only thing i didn't catch, is how to hide buttons and show them only on over.
I noticed the props navButtonsAlwaysVisible and set it to false but it isn't enough.
Should i implement my own logic for that, or maybe I'm just missing something?
here's the component code:
import styles from '../../styles/Testimonial.module.scss'
import Image from 'next/image'
import Carousel from 'react-material-ui-carousel'
const Testimonial = _ => {
const items = [
{
imageUrl: "/png/image0.webp",
feedback: "feedback0",
name: "name0",
location: "location0"
},
{
imageUrl: "/png/image1.jpeg",
feedback: "feedback1",
name: "name1",
location: "location1"
}
]
return (
<div id="customers" className={`section ${styles.testimonial}`}>
<h2 className={`title ${styles.title}`}>Clientes Felizes</h2>
<span className={"separator"}> </span>
<Carousel
className={styles.carousel}
autoPlay={true}
stopAutoPlayOnHover={true}
interval={5000}
animation={"slide"}
swipe={true}
navButtonsAlwaysVisible={false}
navButtonsProps={{
style: {
backgroundColor: "#8f34eb",
opacity: 0.4
}
}}
>
{
items.map( (item, i) => <Item key={i} item={item} /> )
}
</Carousel>
</div>
)
}
function Item(props)
{
return (
<article className={styles.testimonial__card}>
<div className={styles.testimonial__photo_container}>
<Image
className={styles.testimonial__photo}
src={props.item.imageUrl}
alt="Testimonial"
width={312}
height={300}
/>
</div>
<p className={styles.testimonial__copy}>{props.item.feedback}</p>
<span className={styles.testimonial__name}>{props.item.name}</span>
<span className={styles.testimonial__city}>{props.item.location}</span>
</article>
)
}
export default Testimonial;
there's a prop called navButtonsAlwaysInvisible
navButtonsAlwaysInvisible={true}
You can try using Custom CSS for your purpose. Based on the current rendered markup,
.jss6 {
opacity: 0;
transition: all ease 1000ms; /* So that it does not disappear quickly */
}
You can define the hover for the parent so that it displays only when the parent container is hovered on:
.jss1.Testimonial_carousel__3rny3:hover .jss6 {
opacity: 1;
}
This is how it works now:

react wait for another component to finish rendering

I have the following situtation:
2 components A and B.
A is above B in the page layout.
I wish to calculate B height css rule dynamically using it's top.
B's top is affected by A because A is rendered above it. I attached a reference to B and then apply it style by calculating the bounding rect of the ref and calculating the desired height from the top.A problem occurs when component A is taking more time to fully render than component B because A loads images that takes a bit more time to load making B's top to shift a after it was already rendered so the calculating of the height in the function needs to be called again somehow after A was fully rendered but I don't wanna make B coupled to A just because it renders before it, what can I do to solve this issue?
You can solve it using Css flexbox, check code snippet bellow.
(function () {
var loadImgBtn = document.getElementById('load-image-btn');
var loadedImg = document.getElementById('loaded-image');
loadImgBtn.addEventListener('click', function () {
loadedImg.style.display = 'block';
});
})();
.flexbox {
display: flex;
flex-direction: column;
align-items: stretch;
min-height: 350px;
}
#loaded-image {
display: none;
}
#first-block {
background: green;
}
#second-block {
background: red;
flex-grow: 1;
}
<div class="flexbox">
<div id="first-block"> Component A
<img id="loaded-image"
src="https://images.pexels.com/photos/248797/pexels-photo-248797.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500">
</div>
<div id="second-block">Component B</div>
</div>
<button id="load-image-btn">Load Image</button>
If you want to calculate it programmatically you can use ref or forwardRef if you need to pass ref further down something like this
const ComponentA = React.forwardRef((props, ref) => (
<div ref={ref} className="componentA">
{props.children}
</div>
));
const ComponentB = React.forwardRef((props, ref) => (
<div ref={ref} className="componentB">
{props.children}
</div>
));
class App extends React.Component{
constructor(props){
super(props);
this.refA = React.createRef();
this.refB = React.createRef();
}
componentDidMount(){
console.log(this.refA.current.clientHeight,this.refB.current.clientHeight);
}
render(){
return (
<div className="App">
<ComponentA calculatedHeight={componentAHeight} ref={this.refA} >Component A</ComponentA>
<ComponentB calculatedHeight={componentBHeight} ref={this.refB} >Component B</ComponentB>
</div>
);
}
}
You can do it using findDOMNode too (it is depricated in strict mode). react-sizeme might be helpfull as well.

Conditionally inline style a react component based on prop

I need to set the background color of a div based on a prop passed into my react component. Inline styling of React components I am pretty clear on, but I don't know how to correctly apply the inline style to change depending on a prop. I only want to assign the value of the prop rightSideColor in the inline styling of right-toggle if the prop selected is equal true.
export default function UiToggle(props) {
const { leftLabel, rightLabel, selected, rightSideColor, leftSideColor } = props;
return (
<div className="lr-toggle-select" style={{ width: `${width}px` }} >
<div className="lr-gray-background" />
<div>
{leftLabel}
</div>
<div className={'lr-toggle right-toggle' style={{ selected ? (backgroundColor: rightSideColor) : null }}>
{rightLabel}
</div>
</div>
);
}
Fixed a typo - { before className
and you can return an empty object if selected is false else the expected value
Example:
export default function UiToggle(props) {
const { leftLabel, rightLabel, selected, rightSideColor, leftSideColor } = props;
return (
<div className="lr-toggle-select" style={{ width: `${width}px` }} >
<div className="lr-gray-background" />
<div>
{leftLabel}
</div>
<div className='lr-toggle right-toggle' style={ selected ? {backgroundColor: rightSideColor} : {} }}>
{rightLabel}
</div>
</div>
);
}
I would suggest placing all styling and also the conditional operator in a separate const.
export default function UiToggle(props) {
const { leftLabel, rightLabel, selected, rightSideColor, leftSideColor } = props;
const rightToggleStyle = {
backgroundColor: selected ? rightSideColor : null
};
return (
<div className="lr-toggle-select" style={{ width: `${width}px` }} >
<div className="lr-gray-background" />
<div>
{leftLabel}
</div>
<div className="lr-toggle right-toggle" style={rightToggleStyle}>
{rightLabel}
</div>
</div>
);
}
I would try to do the same with the styling of the width. Good luck!
You can conditionally set the value of attributes like style, override them using rules of precedence, and determine whether to include them at all.
export default function UiToggle(props) {
const { leftLabel, rightLabel, selected, rightSideColor, leftSideColor } = props;
//specify style and id (and any other attributes) or don't.
const attrs = selected ? { style: { backgroundColor: "rightSideColor" },id:"hi123" }:{}
//Conditionally override the class names if we want:
if (props.className) attrs.className = props.className
return (
<div className="lr-toggle-select" style={{ width: `${width}px` }} >
<div className="lr-gray-background" />
<div>
{leftLabel}
</div>
{/*Use the spread operator to apply your attributes from attr*/}
{/*Note that the 'id' set below can't be overridden by attrs whereas*/}
{/*className will be. That's because precedence goes from right to left.*/}
{/*Rearrange them to get what you want.*/}
{/*Funky comment format is to make valid JSX and also make SO formatter happy*/}
<div className='lr-toggle right-toggle' {...attrs} id="attrs_cant_override_this_because_its_on_the_right">
{rightLabel}
</div>
</div>
);
}
Try something like this:
<div className='lr-toggle right-toggle' style={ selected ? {backgroundColor: rightSideColor} : '' }}>
{rightLabel}
</div>

Resources