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

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}
`;

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 do I increase blank space padding between header options react

Hi I am trying to figure out how to match my figma design to my react web app, I am trying to increase the blank spacing between the options in the header does anyone know how to do that? Thanks!
Figma image link: https://imgur.com/a/cgmSCr1
Current web app: https://imgur.com/a/cgmSCr1
Code:
import styled from 'styled-components';
import LinkButton from '../../../components/LinkButton';
import { theme } from '../../../styles/theme';
export const HeaderWrapper = styled.header`
box-sizing: border-box;
display: flex;
align-items: center;
justify-content: space-between;
height: 71.5px;
width: 100%;
padding: 80px 38px 0 50px;
margin-bottom: 100px;
`;
export const Logo = styled.img`
margin-left: 43px;
height: 73px;
width: 260px;
margin-top: 10px;
`;
export const NavBar = styled.nav`
margin-right: 43px;
display: flex;
padding-top: 5px;
a {
margin-left: 57px;
text-transform: uppercase;
font-size: 14px;
font-family: ${({ theme }) => theme.font.font3.new};
font-weight: ${({ theme }) => theme.fontWeight.med_700};
}
a:first-of-type {
margin-left: 0px;
}
`;
export const NavButton = styled(LinkButton)`
margin-left: 52px;
text-transform: uppercase;
font-size: 14px;
font-family: ${({ theme }) => theme.font.font3.new};
font-weight: ${({ theme }) => theme.fontWeight.med_700};
`;
export const customStyles = {
overlay: {
backgroundColor: 'rgba(30, 30, 30, .9)',
},
content: {
position: 'absolute',
width: '460px',
height: '718px',
top: '50%',
left: '50%',
background: '#111',
border: `4px solid ${theme.colors.modal.border}`,
borderRadius: '15px',
boxSizing: 'border-box',
transform: 'translate(-50%, -50%)',
},
};
it can be many ways you can do it by giving fix width to the list in header or using grid system like give column to each I think you should do it with padding. Give the padding to a tag on x-axis it will be the good option.
considering your a tag as each item in navbar
a {
//added code
padding-right:40px;
padding-right:40px;
margin-left: 57px;
text-transform: uppercase;
font-size: 14px;
font-family: ${({ theme }) => theme.font.font3.new};
font-weight: ${({ theme }) => theme.fontWeight.med_700};
}

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;

reactjs: I have no idea how to render these components with styled-components

render the BarItem and BarItemSelect inside the link when the is true, they are all set precisely an using a css class, now it's two components...
I don't see a way to do this
const S = {
BarItem: styled.a`
position: relative;
display: block;
height: 3rem;
text-decoration: none;
cursor: pointer;
border: 0;
`,
BarItemSelected: styled.a`
font-weight: 500;
color: var(--dark-text-color);
filter: invert(1);
&:after {
content: '';
position: absolute;
display: block;
width: 100%;
height: 5px;
background-color: white;
border-radius: 5px 5px 0 0;
bottom: 0;
#media (max-width: 63.8rem) {
color: var(--dark-text-color);
filter: invert(1);
background-color: #000;
top: 0;
border-radius: 0 0 5px 5px;
}
}
`,
const SmartLink = ({ href, test, children, ...props }) => {
const router = useRouter();
const isActive = test ? new RegExp(test, 'g').test(router.pathname) : false;
return (
<Link
href={href}
{...props}
>
<a
className={
isActive
? `${styles.barItem} ${styles.barItemSelected}`
: styles.barItem
}
>
{children}
</a>
</Link>
);
};
I can't solve this... does anyone have any suggestions on how I can do it?
The code above is not clear but I'll try to write a pattern in which styled components are used.
styled component
import styled from "styled-components";
const BarItem = styled.a `
position: relative;
display: block;
height: 3rem;
text-decoration:
none;
cursor: pointer;
border: 0;
`;
const BarItemSelected = styled.a`
font-weight: 500;
color: var(--dark-text-color);
filter: invert(1);
&:after {
content: '';
position: absolute;
display: block;
width: 100%;
height: 5px;
background-color: white;
border-radius: 5px 5px 0 0;
bottom: 0;
#media (max-width: 63.8rem) {
color: var(--dark-text-color);
filter: invert(1);
background-color: #000;
top: 0;
border-radius: 0 0 5px 5px;
}
}
`;
Then in the component
import { NavLink} from "react-router-dom";
return (
<NavLink className={isActive
? BarItemSelected
: BarItem} to={href}>
>
{children}
</a>
</NavLink>
);
Please try the above code, if it does'nt work please comment, I'll make the neccessary changes.

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

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

Resources