By using styled components, how can I add some opacity to a background color that comes from an external prop? - reactjs

This is my code, below it you will find the question
import { printIntrospectionSchema } from 'graphql';
import React, { useContext, useState } from 'react';
import styled from 'styled-components';
import { Context } from '../../../Context/Context';
// DATA
function DurationIntervalSelection() {
const tabsData = [
{
text: 'Duration',
},
{
text: 'Interval',
},
];
// STATE
const [selectedIndex, setselectedIndex] = useState(0);
const { selected } = useContext(Context);
console.log(selected.color, 'selected color');
// FUNCTION
const handleIndexSelection = (index) => {
setselectedIndex(index);
};
return (
<Container>
<TabsContainer backgroundColor={selected.backgroundColor}>
<Indicator
backgroundColor={selected.color}
style={{
left: `${selectedIndex * 50}%`,
}}
/>
{tabsData.map((tab, index) => {
return (
<Tab
style={{
color: selectedIndex === index ? 'white' : 'black',
}}
onClick={() => handleIndexSelection(index)}
key={tab.text}
>
<p style={{ zIndex: 100 }}>{tab.text}</p>
</Tab>
);
})}
</TabsContainer>
</Container>
);
}
const Container = styled.div`
margin-top: 10px;
border: 1px solid #f2f2f7;
border-radius: 10px;
box-sizing: border-box;
padding: 10px 0;
`;
const Indicator = styled.div`
width: 50%;
position: absolute;
/* z-index: -1; */
height: 100%;
border-radius: 20px;
cursor: pointer;
transition: all 0.3s;
background-color: ${(props) => props.backgroundColor};
`;
const TabsContainer = styled.div`
display: flex;
width: 100%;
justify-content: space-between;
position: relative;
box-shadow: 1px 1px 3px rgba(0, 0, 0, 0.2);
border-radius: 20px;
overflow: hidden;
background-color: ${(props) => props.backgroundColor};
`;
const Tab = styled.div`
display: flex;
width: 50%;
justify-content: center;
cursor: pointer;
align-items: center;
padding: 10px;
`;
export default DurationIntervalSelection;
As you can see from the above code i pass backgroundColor as a prop that takes some color from a React state.
<TabsContainer backgroundColor={selected.backgroundColor}>
And in the styled component I do:
background-color: ${(props) => props.backgroundColor};
But my question is, since i need to follow a design made by a colleague, how do i add opacity to the above background color without affecting the opacity of the whole div: TabsContainer. I mean, if i add on the TabsContainer -> opacity: 0.3 - for instance the whole TabsContainer div will be affected by the opacity, including the Tab div, while what I want is just to change opacity on the color itself so i do not affect any child. I hope it makes sense. Is there a way?

Okay if your hex value comes from your backend, you can either create your own javascript function that converts hex to rgba or you can use a library like polished. They have a function named rgba that converts a hex string and adds an alpha value to it
import { rgba } from 'polished'
const div = styled.div`
background: ${(props) => rgba(props.backgroundColor, 0.3)};
`
Or you can apply it directly to the prop
<TabsContainer backgroundColor={rgba(selected.backgroundColor, 0.3)}>
Example CodeSandbox.

Since the data from the backend where right but I could not find a solution I have realised that I could have added to
<TabsContainer backgroundColor="rgba(255,255,255, 0.5)">
A background color on the white notes with opacity so to emphasise the color behind it in a lighter way

Related

How to use event handler with inside a styled component

import styled from "styled-components";
import pic from "./assets/images/bg-sidebar-desktop.svg";
const App=()=> {
const [index, setIndex] = useState(0);
const navitems = [
{
step: "Step 1",
value: "Your info",
},
{
step: "Step 2",
value: "Select plan",
},
{
step: "Step 3",
value: "Add-ons",
},
{
step: "Step 4",
value: "Summary",
},
];
return (
<Container>
<Navbar imgUrl={pic}>
{navitems.map((item, key) => {
return (
<>
<Index onClick={(key)=>setIndex(key)}>{key + 1}</Index>
<Heading>{item.step}</Heading>
<Content>{item.value}</Content>
</>
);
})}
</Navbar>
</Container>
);
}
const Container = styled.div`
height: 70.5vh;
width: 55vw;
margin: auto;
margin-top: calc(100vh / 7);
border-radius: 1em;
background-color: white;
overflow: hidden;
font-size: .9em;
`;
const Navbar = styled.div`
border: 1px solid black;
background-image: url(${(props) => props.imgUrl});
background-repeat: no-repeat;
background-position: 100% 100%;
height: 66.7vh;
width: 15.5vw;
border-radius: 1em;
margin-top: calc((3.6vh) / 2);
margin-left: 0.8em;
color: #ffffff;
text-transform: uppercase;
`;
const Heading = styled.div`
// border: 1px solid red;
color: hsl(231, 11%, 63%);
text-indent: 5.5em;
letter-spacing: .005em;
font-size: .9em;
`;
const Content = styled.div`
// border: 1px solid white;
text-indent: 5em;
letter-spacing: .1em;
font-weight: bolder;
`;
const Index = styled.span`
border: 1px solid white;
display: inline-block;
border-radius: 50%;
height: 2em;
width: 2em;
text-align: center;
padding-top: 0.3em;
box-sizing: border-box;
position: relative;
top: 7%;
left: 10%;
`;
export default App;
NOTE: There is an Index component and a useState variable whose name is also index. Don't get confused.
I want that everytime I click on the Index component the index useState variable gets updated to that particular key value .The above code applies the inline event handler to Index component but index state variable is not changed correctly on clicking that.On console logging the index a string gets output .Here's the string
"SyntheticBaseEvent {_reactName: 'onClick', _targetInst: null, type: 'click', nativeEvent: PointerEvent, target: span.sc-eDvSVe.iTaECf, …}"
Do this:
<Index onClick={() => setIndex(key)}>{key + 1}</Index>
Explaination:
// Normal syntax for onClick:
onClick = {(event) => someFunc()}
// Your Code
// here you pass key as an argument so key here means click event
// so what you give setIndex is the click event and not the key
onClick = {(key) => setIndex(key)}
In your case "key" is event, which returns from the button:
onClick={(key)=>setIndex(key)
just remove then "key" from params of func, then key will be take from array index:
<Navbar imgUrl={pic}>
{navitems.map((item, index) => {
return (
<>
<Index onClick={()=>setIndex(index)}>{index + 1}</Index>
<Heading>{item.step}</Heading>
<Content>{item.value}</Content>
</>
);
})}
</Navbar>

How to inherit styles from another styled component and turning regular component into styled component at the same time?

I am using StyledComponents stying framework and This is my regular react component
const SelectButton = ({className,children, ...rest}) => {
return (
<select className = {className}{...rest}>
{children}
</select>
);
}
I want to turn this component into styled component by calling styled() function and for that purpose I have attached className prop to DOM element of my react component (SelectButton).
export const StyledSelectButton = styled(SelectButton);
But instead of putting the css in this styled component, I want to inherit from different styled component which is StyledButton.js, which has following css properties.
export const StyledButton = styled(Button).attrs(({ type }) => ({
type: type || "button",
}))
display: inline-block;
height: auto;
padding: 0.8rem 2rem;
border: none;
border-radius: 6px;
font-weight: 500;
font-size: 1.6rem;
text-decoration: none;
text-transform: capitalize;
cursor: pointer;
overflow: hidden;
background-color: ${({ primary }) => (primary ? "#646ff0" : "#cccdde")};
color: ${({ primary }) => (primary ? "white" : "#646681")};
.__select {
color: #585858;
font-family: Poppins;
padding: 1rem;
border: none;
background-color: #cccdde;
width: 150px;
cursor: pointer;
};
How can I achieve that?
I have tried doing this way , but I am repeating my code.
export const StyledSelectButton = styled(SelectButton)
display: inline-block;
height: auto;
padding: 0.8rem 2rem;
border: none;
border-radius: 6px;
font-weight: 500;
font-size: 1.6rem;
text-decoration: none;
text-transform: capitalize;
cursor: pointer;
overflow: hidden;
background-color: ${({ primary }) => (primary ? "#646ff0" : "#cccdde")};
color: ${({ primary }) => (primary ? "white" : "#646681")};
&__select {
color: #585858;
font-family: Poppins;
padding: 1rem;
border: none;
background-color: #cccdde;
width: 150px;
cursor: pointer;
}
You can do something like this,
import styled, {css} from "styled-components";
import { StyledButton } from './Button';
const style = css`
color: #585858;
font-family: Poppins;
padding: 1rem;
border: none;
background-color: #cccdde;
width: 150px;
cursor: pointer;
`;
Using function declaration method:
export function StyledSelectButton({ className, children, ...rest }){
return (
<select className={className} {...rest}>
{children}
</select>
);
};
To turn this component into a styled component, pass it to the styled() function.
StyledSelectButton = styled(StyledButton).attrs((props) => ({
as: "select"
}))`
${style}
`;

react transition effect not work after async thunk

Although I have updated the todo status, the checkbox effect is not working correctly, as if no effect has been applied, what could be the reason for this? I don't think there is a problem with the api file, but the api request is taking a long time.I think it's because css doesn't render again, I can't think of anything else..
Thank you for helping
import React from "react";
import { useDispatch } from "react-redux";
import { toggleTodos } from "../redux/slice/thunkActions";
import styled from "styled-components";
const Content = styled.div`
color: #fff;
text-transform: capitalize;
`;
const Options = styled.div`
display: flex;
align-items: center;
justify-content: center;
gap: 2rem;
`;
const EditButton = styled.button`
cursor: pointer;
background-color: #ff6b81;
padding: 0.7rem 2rem;
color: #fff;
border-radius: 0.5rem;
font-weight: bold;
`;
const InputWrapper = styled.label`
position: relative;
`;
const Input = styled.input`
position: absolute;
left: -99999px;
top: -99999px;
&:checked + span {
background-color: #1890ff;
transition: 1s;
&:before {
left: calc(100% - 0.2rem);
transform: translateX(-100%);
}
}
`;
const Slider = styled.span`
display: flex;
width: 5rem;
height: 2.5rem;
cursor: pointer;
border-radius: 10rem;
background-color: #fcebb6;
transition: background-color 0.4s;
&:before {
content: "";
position: absolute;
top: 0.2rem;
left: 0.2rem;
width: 2.1rem;
height: 2.1rem;
border-radius: 2.1rem;
transition: 1s;
background-color: #fff;
}
`;
const Todo = ({ todo }) => {
const dispatch = useDispatch();
const handleChange = (todo) => {
dispatch(toggleTodos(todo));
};
return (
<li>
<Content>{todo.content}</Content>
<Options>
<EditButton type="button">Edit</EditButton>
<InputWrapper htmlFor={`todoContent${todo.id}`}>
<Input
id={`todoContent${todo.id}`}
type={"checkbox"}
onChange={() => handleChange(todo)}
checked={todo && todo.isCompleted}
/>
<Slider />
</InputWrapper>
</Options>
</li>
);
};
export default Todo;

Flexbox Container with Child in it with position absolute

I'm new to React, and I'm currently building a slideshow on my website. Basically, I have a left arrow, the slide content, then the right arrow in my flexbox for my slideshow. However, to make my arrows on the edges of the screen I needed to use position absolute, which messes up my flexbox container. I figured out that absolutely positioned child items don't count in the flexbox of the parent, but is there a way around that? As of now, my image is overlapping with the left arrow. Thanks, and sorry if this is poorly written since I'm very new to this all. Code will be below.
Image: [1]: https://i.stack.imgur.com/PkL3Z.jpg
import { ArrowBackIosOutlined, ArrowForwardIosOutlined } from '#material-ui/icons'
import React from 'react'
import styled from 'styled-components'
import grocery from '../assets/grocery.png'
const Container = styled.div`
width: 100%;
height: 100vh;
display: flex;
position: relative;
`
const Arrow = styled.div`
width: 50px;
height: 50px;
background-color: #fff7f7;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
position: absolute;
top: 0;
bottom: 0;
left: ${props => props.direction === "left" && "10px"};
right: ${props => props.direction === "right" && "10px"};
margin: auto;
cursor: pointer;
opacity: 0.5;
`
const Wrapper = styled.div`
height: 100%;
`
const Slide = styled.div`
width; 100vw;
height: 100vh;
display: flex;
align-items: center;
`
const ImageContainer = styled.div`
height: 100%;
flex: 1;
margin-top: 50px;
`
const Image = styled.img`
height: 50%;
`
const InfoContainer = styled.div`
flex: 1;
`
const Slider = () => {
return (
<Container>
<Arrow direction="left">
<ArrowBackIosOutlined/>
</Arrow>
<Wrapper>
<Slide>
<ImageContainer>
<Image src={https://images.unsplash.com/photo-1481349518771-20055b2a7b24?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxzZWFyY2h8M3x8cmFuZG9tfGVufDB8fDB8fA%3D%3D&w=1000&q=80}/>
</ImageContainer>
</Slide>
</Wrapper>
<Arrow direction="right">
<ArrowForwardIosOutlined/>
</Arrow>
</Container>
)
}
export default Slider

styled-component dropdown make parent:hover color stay while child:hover

I'm trying to make the parent background color stay changed on hover as I continue to hover over the dropdown items.
https://zqy0v.csb.app/dropdowns < dropdown
import React from "react";
import styled from "styled-components";
//============================================ styles =============================================
const DivDropdownContent = styled.div`
display: none;
position: absolute;
background-color: #f9f9f9;
min-width: 24.7rem;
box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
z-index: 1;
`;
const DivDropdown = styled.div`
position: relative;
display: inline-block;
&:hover ${DivDropdownContent} {
display: block;
}
`;
const SpanDropdownTitle = styled.div`
font-size: 1.6rem;
font-weight: bold;
padding: 2rem 6rem;
border-radius: 0.6rem;
border: 1px solid black;
&:hover {
cursor: pointer;
}
`;
const ItemDropdown = styled.p`
padding: 1rem;
&:hover {
cursor: pointer;
background: lightgray;
}
`;
//=========================================== component ===========================================
const BasicDropdown = props => {
return (
<DivDropdown>
<SpanDropdownTitle>Basic Dropdown</SpanDropdownTitle>
<DivDropdownContent>
<ItemDropdown>Item 1</ItemDropdown>
<ItemDropdown>Item 2</ItemDropdown>
<ItemDropdown>Item 3</ItemDropdown>
</DivDropdownContent>
</DivDropdown>
);
};
export default BasicDropdown;
Basically I would like the background color to stay changed for the parent while hovering over the child items in the dropdown, much like is done here https://woocommerce.com/
Is there an easy way to do this, or do I have to start getting complicated with using state and onPointerEnter and onPointerLeave?
I finally ended up finding the solution, and am a bit embarrassed.
const DivDropdown = styled.div`
position: relative;
display: inline-block;
&:hover ${DivDropdownContent} {
display: block;
}
`;
The Issue: ^This was only targeting the nested component when I added the background cover to the hover.
const DivDropdown = styled.div`
position: relative;
display: inline-block;
&:hover {
background: lightgray;
}
&:hover ${DivDropdownContent} {
display: block;
}
`;
The Fix: ^By adding the above, I was able to correct the behavior.
I'm going to leave this question up, because I wasn't able to find much tutorials on this through my internet searching. I think this is a fairly clean solution and think it will help others searching.

Resources