Conditional rendering of CSS style in elements React - css

I'm trying to make a signal bar which depending on the number of strength (1-3) will display the corresponding number of bars in black (activated) otherwise in grey colour. So in React i have used the following:
class Application extends React.Component {
signalBar{
switch(this.props.signal-strength) {
case 1:
< className={{'first-bar, signal-bars, bar'}} style={{display: 'block', color 'black'}}>
< className={{'second-bar, signal-bars, bar'}} style={{display: 'block', color 'grey'}}>
< className={{'third-bar, signal-bars, bar'}} style={{display: 'block', color 'grey'}}>
break;
case 2:
< className={{'first-bar, signal-bars, bar'}} style={{display: 'block', color 'black'}}>
< className={{'second-bar, signal-bars, bar'}} style={{display: 'block', color 'black'}}>
< className={{'third-bar, signal-bars, bar'}} style={{display: 'block', color 'grey'}}>
case 3:
< className={{'first-bar, signal-bars, bar'}} style={{display: 'block', color 'black'}}>
< className={{'second-bar, signal-bars, bar'}} style={{display: 'block', color 'black'}}>
< className={{'third-bar, signal-bars, bar'}} style={{display: 'block', color 'black'}}>
break;
default:
< className={{'first-bar bar'}} style={{display: 'block', color 'grey'}}>
< className={{'second-bar bar'}} style={{display: 'block', color 'grey'}}>
< className={{'third-bar bar'}} style={{display: 'block', color 'grey'}}>
}
}
render() {
return <div className={{sizing-box}}>
<div className={{signal-bars, bar}}>
{this.signalBar}
</div>
</div>
<p>
</p>
</div>;
}
}
React.render(<Application />, document.getElementById('app'));
CSS:
html, body
height: 100%
body
background: #333
display: flex
justify-content: center
align-items: center;
{ box-sizing: border-box; }
.sizing-box {
height: 50px;
width: 80px;
}
.signal-bars {
display: inline-block;
}
.signal-bars .bar {
width: 14%;
margin-left: 1%;
min-height: 20%;
display: inline-block;
}
.signal-bars .first-bar { height: 30%; }
.signal-bars .second-bar { height: 60%; }
.signal-bars .third-bar { height: 90%; }
The value of signal-strength is not static and can change depending on pros from the parent element. The error i'm getting is 'this is a reserved word'. How can someone inject the function 'signalBar' in a React element? Is there a more 'simple' way to do this with less coding in switch condition?

With inline styles, you can do some computed styles like this :
const colorScheme = {
first: ['grey', 'black', 'black', 'black'],
second: ['grey', 'grey', 'black', 'black'],
third: ['grey', 'grey', 'grey', 'black'],
}
class Application extends React.Component {
render() {
const colorNb = ((this.props.signal-strength < 4) && (this.props.signal-strength > 0)) ? this.props.signal-strength : 0;
return (
<div className={{sizing-box}}>
<div className={{signal-bars, bar}}>
<div className={{'first-bar, signal-bars, bar'}} style={{display: 'block', color: colorScheme.first[colorNb] }} />
<div className={{'second-bar, signal-bars, bar'}} style={{display: 'block', color: colorScheme.second[colorNb] }} />
<div className={{'third-bar, signal-bars, bar'}} style={{display: 'block', color: colorScheme.third[colorNb] }} />
</div>
</div>
);
}
}
If you have control over your css you can also use the child selector and the inheritance to use less classeNames on your bars :
.signal-bars {
display: inline-block;
}
.signal-bars div {
width: 14%;
margin-left: 1%;
min-height: 20%;
display: block;
}
.signal-bars div:nth-child(1) { height: 30%; }
.signal-bars div:nth-child(2) { height: 60%; }
.signal-bars div:nth-child(3) { height: 90%; }
Then your component will be cleaner :
return (
<div className="sizing-box">
<div className="signal-bars">
<div style={{ color: colorScheme.first[colorNb] }} />
<div style={{ color: colorScheme.second[colorNb] }} />
<div style={{ color: colorScheme.third[colorNb] }} />
</div>
</div>
);

I like to use the classnames package from npm.
For example:
<div className={classnames('first-bar', {'signal-bars': this.state.signal-strength === 1})} />
Alternatively you can move all of the logic outside of the DIV itself:
const divClasses = classnames('first-bar', {
'signal-bars': this.state.signal-strength === 1
})
// ...
<div className={divClasses} />

Related

Make a panel under a button that overlays another element

I have an editor and several buttons above it on the right. I would like to have a panel just under Button2 that overlays the editor. Then, clicking on Button2 will expand and collapse the panel (which will be easy to implement).
I have written the following code: https://codesandbox.io/s/fervent-mclaren-3mrtyj?file=/src/App.js. At the moment, the panel is NOT under Button2 and does NOT overlay the editor.
Does anyone know how to amend the CSS?
import React from "react";
import { Stack } from "#fluentui/react";
export default class App extends React.Component {
render() {
return (
<div>
<Stack horizontal horizontalAlign="space-between">
<div>Title</div>
<div>Button1 Button2 Button3</div>
</Stack>
<div
style={{
backgroundColor: "yellow",
width: "350px",
height: "50px"
}}
>
A floating panel which is supposed to be always under "Button2" and
overlays the editor.
</div>
<div
style={{
backgroundColor: "gray",
width: "100%",
height: "300px"
}}
>
An editor
</div>
</div>
);
}
}
You need to use position:absolute on floating pane and add it in the editor div which will have position:relative.You can see the result it works fine
On clicking button 2 the floating panel hides/shows alternatively
This will work.
var btn=document.querySelector('.drop_btn');
btn.onclick=function()
{
document.querySelector('.dropdown').classList.toggle('block');
}
*
{
font-family: 'arial';
margin: 0px;
padding: 0px;
}
.menu_pane
{
display: flex;
background: #151515;
color: white;
padding:5px 10px;
align-items: center;
border-bottom: 1px solid rgba(255,255,255,0.2);
}
.menu_pane h3
{
font-weight: normal;
font-size: 18px;
flex-grow: 1;
}
.menu_pane .btn button
{
position: relative;
background: #0971F1;
color: white;
border-radius: 5px;
border:none;
cursor: pointer;
padding: 8px 20px;
margin-right: 10px;
}
.dropdown
{
display: none;
height: 100%;
width: 100%;
top: 0;
left: 0;
color: white !important;
position: absolute;
background: #242424;
border-radius: 0 0 10px 10px;
}
.menu_pane .btn .dropdown p
{
font-size: 14px;
}
.editor_pane
{
position: relative;
background:#151515;
color: white;
min-height: 50vh;
border-radius: 0 0 10px 10px;
padding: 10px;
color: #512DA8;
}
.block
{
display: block;
}
<div class="container">
<div class="menu_pane">
<h3>Title</h3>
<div class="btn">
<button>Button-1</button>
</div>
<div class="btn">
<button class="drop_btn">Button-2</button>
</div>
<div class="btn">
<button>Button-3</button>
</div>
</div>
<div class="editor_pane">
<p>An editor</p>
<div class="dropdown">
<p>A floating panel which is supposed to be always under "Button2" and overlays the editor.</p>
</div>
</div>
</div>
How does this look?
https://codesandbox.io/s/hidden-platform-q3v4kc?file=/src/App.js
I moved the floating pane into the button, made the button position relative, and made the floating pane position absolute.
Note: notice there's no top property on the floating pane. One neat thing about position absolute is if you don't set top, left, bottom, right those positions will be where that box would be if it wasn't position absolute.
Update
I noticed that the overlay needed to cover the "editor" area only and have the example updated with hopefully the right placement of it.
Updated live example: codesandbox
import React from "react";
import { Stack } from "#fluentui/react";
export default class App extends React.Component {
state = { showOverlay: true };
handleToggle = () =>
this.setState((prev) => ({ showOverlay: !prev.showOverlay }));
render() {
return (
<div>
<Stack
horizontal
horizontalAlign="space-between"
style={{ padding: "12px" }}
>
<div>Title</div>
<Stack horizontal>
<button>Button1</button>
<button onClick={this.handleToggle}>
{`Button2 (${this.state.showOverlay ? "Hide" : "Show"} Overlay)`}
</button>
<button>Button3</button>
</Stack>
</Stack>
<div
style={{
backgroundColor: "gray",
width: "100%",
height: "300px",
position: "relative"
}}
>
An editor
<div
style={{
position: "absolute",
inset: "0",
backgroundColor: "rgba(0, 0, 0, 0.70)",
display: this.state.showOverlay ? "flex" : "none",
justifyContent: "center",
alignItems: "center",
color: "#fff"
}}
>
A floating panel which is supposed to be always under "Button2" and
overlays the editor.
</div>
</div>
</div>
);
}
}
Keeping the original example (it had overlay on the whole component except for "Button 2") just in case if it might be useful.
Original
Not sure if I fully understand the desired result, but here is the component implemented with a toggle overlay controlled by Button2.
The overlay is currently set on top of and blocking all child elements except for Button2, so that it works as a "start editing" button, but it can be further adjusted to specify which element it covers to better suit the use case.
Quick demo of the example: codesandbox
import React from "react";
import { Stack } from "#fluentui/react";
export default class App extends React.Component {
state = { showOverlay: true };
handleToggle = () =>
this.setState((prev) => ({ showOverlay: !prev.showOverlay }));
render() {
return (
<div style={{ position: "relative", zIndex: "1" }}>
<Stack
horizontal
horizontalAlign="space-between"
style={{ padding: "12px" }}
>
<div>Title</div>
<Stack horizontal>
<button>Button1</button>
<button style={{ zIndex: "75" }} onClick={this.handleToggle}>
{`Button2 (${this.state.showOverlay ? "Hide" : "Show"} Overlay)`}
</button>
<button>Button3</button>
</Stack>
</Stack>
<div
style={{
position: "absolute",
inset: "0",
backgroundColor: "rgba(0, 0, 0, 0.70)",
zIndex: "50",
display: this.state.showOverlay ? "flex" : "none",
justifyContent: "center",
alignItems: "center",
color: "#fff",
}}
>
A floating panel which is supposed to be always under "Button2" and
overlays the editor.
</div>
<div
style={{
backgroundColor: "gray",
width: "100%",
height: "300px",
}}
>
An editor
</div>
</div>
);
}
}

Why is flex container wrapper the flex items despite exceeding 100%?

I want to make a 3 x 6 matrix. I used flexbox and all the flexItems have a flex-basis of 1/6.
At full screen, its how I want it. However, if you make it a smaller screen it starts to wrap. I don't want to break the 3 x 6
https://codesandbox.io/s/vibrant-spence-gski65
import "./styles.css";
import React, { useState } from "react";
const gridValues = new Array(18).fill(0);
export default function App() {
const [grid, setGrid] = useState<number[]>(gridValues);
return (
<div
style={{
width: "90%",
height: "100%"
}}
>
<div
style={{
display: "flex",
flexWrap: "wrap",
padding: "16px"
}}
>
{grid.map((num, i) => {
return (
<span
key={i}
style={{
display: "flex",
flexBasis: "16.666%",
cursor: "pointer",
justifyContent: "center",
padding: "16px",
border: "1px solid black",
flexShrink: 0
}}
>
<span style={{ opacity: 0 }}>{num}</span>
</span>
);
})}
</div>
</div>
);
}
https://codesandbox.io/s/vibrant-spence-gski65?file=/src/App.tsx
Ended up using CSS grid instead after listening to comment. Definitely much easier
import "./styles.css";
import React, { useState } from "react";
const gridValues = new Array(18).fill(0);
export default function App() {
const [grid, setGrid] = useState<number[]>(gridValues);
return (
<div
style={{
width: "90%",
height: "100%"
}}
>
<div
style={{
display: "grid",
gridTemplateColumns: "1fr 1fr 1fr 1fr 1fr 1fr",
gridTemplateRows: "1fr 1fr 1fr"
}}
>
{grid.map((num, i) => {
return (
<span
key={i}
style={{
display: "flex",
cursor: "pointer",
justifyContent: "center",
padding: "16px",
border: "1px solid black"
}}
>
<span style={{ opacity: 0 }}>{num}</span>
</span>
);
})}
</div>
</div>
);
}

Scrolling scrollable div freezes moving content

When I vertically scroll the moving div, some of the content freezes. I'm wondering how I would fix this. It isn't consistent either, as clicking the start/stop button sometimes fixes the issue for a few seconds. Very confused.
import { useEffect, useRef, useState } from "https://cdn.skypack.dev/react"
import ReactDOM from "https://cdn.skypack.dev/react-dom"
const Graph = ({ references: { trackerRef, wholeRef } }) => {
return (
<div
ref={wholeRef}
style={{
overflow: 'scroll',
height: '400px',
backgroundColor: '#333',
cursor: 'default',
userSelect: 'none'
}}
>
<div style={{ position: 'relative' }}>
<div>
{(() => {
const items = []
for (let i = 1; i < 100; i++) {
items.push(
<div
key={i}
style={{
position: 'absolute',
left: i * 1000,
height: '100%',
display: 'flex',
}}
>
<div
style={{
width: '1px',
backgroundColor: '#888',
}}
></div>
<div style={{ color: '#ddd', marginLeft: 8, fontSize: 14 }}>
{i}s
</div>
</div>
)
}
return items
})()}
{(() => {
const items = []
for (let i = 1; i < 1000; i++) {
if ((i * 100) % 1000 === 0) continue
items.push(
<div
key={i}
style={{
position: 'absolute',
left: i * 100,
height: '100%',
display: 'flex',
}}
>
<div
style={{
width: '1px',
backgroundColor: '#555',
}}
></div>
<div style={{ color: '#aaa', marginLeft: 5, fontSize: 10 }}>
{i * 100}ms
</div>
</div>
)
}
return items
})()}
<div
ref={trackerRef}
style={{
position: 'absolute',
height: '100%',
display: 'flex',
width: '1px',
backgroundColor: 'lightgreen',
}}
></div>
</div>
<div>
<div style={{ height: '2000px', width: '20px' }}></div>
</div>
</div>
</div>
)
}
const App = () => {
const trackerRef = useRef(null)
const wholeRef = useRef(null)
const [paused, setPaused] = useState(false)
const animationFrames = useRef([]).current
const intervals = useRef([]).current
const time = useRef(0)
useEffect(() => {
// Increase time when unpaused
intervals.push(setInterval(() => !paused && (time.current += 1), 1))
}, [paused])
useEffect(() => {
const refreshTrackbar = () => {
if (trackerRef.current && wholeRef.current && !paused) {
trackerRef.current.style.left = time.current + 'px'
wholeRef.current.scrollLeft = time.current - 100
requestAnimationFrame(refreshTrackbar)
}
}
animationFrames.push(requestAnimationFrame(refreshTrackbar))
}, [paused])
return (
<>
<h1>Scrollbug</h1>
<button
onClick={() => {
if (paused) {
setPaused(false)
} else {
setPaused(true)
animationFrames.forEach(frame => cancelAnimationFrame(frame))
intervals.forEach(interval => clearInterval(interval))
}
}}
>
{paused ? 'Start' : 'Stop'}
</button>
<br />
<br />
<Graph references={{ trackerRef, wholeRef }} />
</>
)
}
ReactDOM.render(<App />, document.getElementById("root"))
Here is a codepen to test the issue yourself
https://codepen.io/springer268/pen/PomjVvw
EDIT: So I tried this codepen on my mac, and the bug does not happen, which leads me to believe this is a Chrome version/platform specific issue, and not a me issue.
I'm not really sure how to make it stop freezing, but if you added an overflow:scroll; to your #root with a bigger height than your side-way scrolling div, you could scroll over it without freezing.
Making the side-way scrolling div a specific height and overflow-y: hidden; could help as well.
Kind of a workaround, but it works.

how to show image over blurred background

I have the following code:
const [hover, setHover] = useState(false);
<Paper
onMouseOver={() => setHover(true)}
onMouseOut={() => setHover(false)}
style={{
width: '100%',
height: 445,
boxShadow: '0px 2px 5px ' + Colors.third + '66',
backgroundRepeat: 'no-repeat',
backgroundPosition: 'center center',
backgroundImage: hover ? `url(${preview})` : ''
}}
className={hover ? 'image-paper' : ''}
>
some test text
</Paper>
and the following css:
.image-paper {
filter: blur(6px);
-webkit-filter: blur(6px);
}
above is the result:
and above is the goal:
the unblured element element cannot be a child of the blured element,
here a possible exemple of two stacked element with only one blured (those 2 img can be any other tag with content):
.Overlay {
display: grid;
justify-content: center;
}
img {
grid-row: 1;
grid-column: 1;
object-fit: scale-down;
filter: blur(0);
}
.blur {
filter: blur(5px) hue-rotate(160deg);
}
<div class="Overlay">
<img src="https://pngimg.com/uploads/mars_planet/mars_planet_PNG7.png" width="640" height="480" class="blur" />
<img src="https://pngimg.com/uploads/avatar/avatar_PNG29.png" width="640 " height="480 " />
</div>

React / Material UI - <CardHeader> css

Using React & Material UI I'm trying to layout 3 divs within a <Card> <CardHeader/> such that it has a left, center and right alignment respectively as shown below.
The change is trivial, I need to remove the padding and change to display: inherit but it seems this <div> exists between the exposed style & titleStyle for <CardHeader> and <CardHeader title={someElement}/>
The hierarchy looks like:
...<div><div.myCardHeader><div><span><myTitleElement>...
Being so new to React and styles, I'm unsure how to get to it.
Some representative code follows.
Thanks for help.
// #flow
import React, { Component } from 'react';
import Paper from 'material-ui/Paper';
import { Card, CardActions, CardHeader, CardMedia, CardTitle, CardText } from 'material-ui/Card';
const style = {
paper: {
height: 250,
width: 200,
margin: 20,
},
card: {
header: {
container: {
display: 'flex', /* establish flex container */
justifyContent: 'space-between',
backgroundColor: 'lightblue'
},
padding: 1,
height: 26
}
}
};
const POCardTitle = () => (
<div className="myContainer" style={style.card.header.container}>
<div style={{ width: 25, height: 26, border: '2px dashed red' }}> - </div>
<div style={{ width: 25, height: 26, border: '2px dashed blue' }}> - </div>
<div style={{ width: 25, height: 26, border: '2px dashed green' }}> - </div>
</div>
);
export default class POCard extends Component {
render() {
return (
<div>
<Paper style={style.paper} zDepth={2} >
<Card >
<CardHeader className="myCardHeader"
style={style.card.header}
titleStyle={{ paddingRight: 0, display: 'inline' }}
title={<POCardTitle />}
/>
</Card>
</Paper>
</div>
);
}
}
I managed to get there courtesy of https://www.styled-components.com
and the following:
const StyledHeader = styled(CardHeader) `
padding: 0px !important;
height: 26px !important;
> div {
display: inherit !important;
padding-right: 0px !important;
}
`;
I could find no other way to get to the "first div" after the component through regular CSS...

Resources