I have a button component:
import React from 'react';
import styled from 'styled-components';
import StyledInput from './NoteWindow'
const StyledButton = styled.button`
border: none;
background: ${props => props.color};
color: white;
font-size: 1.5em;
border-radius: 10px;
padding: .3em;
width: 5em;
height: 2em;
margin-right: 20px;
font-family: 'Montserrat', sans-serif;
font-weight: 600;
cursor: pointer;
transition: ease-in-out 250ms;
&:focus {
outline: none;
}
&:hover {
background: white;
color: ${props => props.color};
border: ${props => props.color} 1.5px solid;
transition: ease-in-out 250ms;
}
`;
const Button = ({ color, name, remove }) => {
return (
<StyledButton color={color} remove={remove} onClick={remove == 'true' ? StyledInput.value = '' : false}>{name}</StyledButton>
)
};
export default Button;
and an input component:
import React from 'react';
import Button from './Button';
import styled from 'styled-components';
const NoteWindow = (props) => {
return (
<StyledNoteWindow className="NoteWindow">
<StyledForm action="#" className="form">
<StyledInput type="text" name="title" id="title" className="inp" autoComplete="off" placeholder="Title" style={{fontSize: 60, fontWeight: 700}}/>
<StyledInput type="text" name="content" id="content" className="inp" autoComplete="off" placeholder="Content.." style={{fontSize: 20}}/>
</StyledForm>
<StyledButtonsContainer>
<Button name="Discard" color={red} remove='true'/>
<Button name="Save" color={blue}/>
</StyledButtonsContainer>
</StyledNoteWindow>
)
}
export default NoteWindow;
<Button name="Discard" color={red} remove='true'/>
Objective: if the remove attribute equales to 'true' remove the input data of the input component, else, do nothing.
Is there a way to do that? Thanks in advance.
It's telling me that there's only code so I'm adding some text
Related
I have a main page, with a button component i create to reuse in my project. My issue is when i add the onClick event to my external component, the click event is not working, but is i create the same button inside my main page, the click event works just fine
Button Component
import React from "react";
import styled from "styled-components";
const BigButton = (props): JSX.Element => {
return <>{props.red ? <BigBtn red={props.red}>{props.val}</BigBtn> : <BigBtn>{props.val}</BigBtn>}</>;
};
export default BigButton;
const BigBtn = styled.button`
font-style: normal;
font-weight: 500;
font-size: 12px;
line-height: 15px;
color: #f5f5f5;
width: 78px;
height: 30px;
background: ${(props) => (props.red ? "#BD2129" : "#2e3034")};
border: ${(props) => (props.red ? "initial" : "1px solid #494b4f")};
border-radius: 2px;
display: flex;
align-items: center;
justify-content: center;
`;
This works on main page
<button onClick={buttonClose}>Close</button>
Button Component on main page - This doesn't work on main page
<BigButton val="Cancel" onClick={handleClose} />
Close function
const handleClose = (e) => {
e.preventDefault();
props.onClose();
};
Your component does not look correct. You do not have button inside the component and onClick event. You should update like this
import React from "react";
import styled from "styled-components";
const BigButton = (props): JSX.Element => {
const handleClick = () => {
props.onClick()
}
return <>{props.red ?
<BigBtn red={props.red}>
<button onClick={handleClick}>
{props.val}
</button>
</BigBtn> :
<BigBtn>
<button onClick={handleClick}>
{props.val}
</button>
</BigBtn>}
</>
};
export default BigButton;
const BigBtn = styled.button`
font-style: normal;
font-weight: 500;
font-size: 12px;
line-height: 15px;
color: #f5f5f5;
width: 78px;
height: 30px;
background: ${(props) => (props.red ? "#BD2129" : "#2e3034")};
border: ${(props) => (props.red ? "initial" : "1px solid #494b4f")};
border-radius: 2px;
display: flex;
align-items: center;
justify-content: center;
`;
i am new to TS and I have been asked to move existing JS code base to ts. I have styled component which looks like this (style.js)
import styled from "styled-components";
export const Container = styled.div`
${({ flex }) => flex && `flex: ${flex};`}
${({ flex }) => flex && `display: flex;`}
flex-direction: column;
`;
export const Label = styled.label`
display: inline-block;
color: #95aac9;
font-size: 12px;
`;
export const DefaultInput = styled.input`
border: 1px solid #dfe0eb;
background-color: transparent;
padding: 10px 12px;
border-radius: 4px;
height: 35px;
color: #888888;
font-weight: 500;
&:focus {
outline: none;
}
`;
export const GrayInput = styled.input`
border: none;
background-color: #ebf2fb;
border: 1px solid #e1e9f5;
border-radius: 5px;
padding: 5px 10px;
&:focus {
outline: none;
}
`;
I was writting types for the file where I am importing this
import React from "react";
import Label from "components/atoms/Label";
import { DefaultInput, GrayInput, NormalInput, Container } from "./styles";
export default function Input({flex, theme, ...props}:{flex:string, theme}) {
return (
<Container flex={props.flex}>
{props.label && <Label>{props.label}</Label>}
{(!props.theme || props.theme === "light") && <DefaultInput {...props} />}
{props.theme === "gray" && <GrayInput {...props} />}
{props.theme === "normal" && <NormalInput {...props} />}
</Container>
);
}
but I can't figure the type for the {...props] in export default function Input({flex, theme, ...props}:{flex:string, theme}) { and how to write it
I think this should do the work:
export default function Input({flex, theme, ...props}:{flex:string; theme: string; [rest: string]: any })
You should also use flex and theme variables directly instead of props.flex and props.theme, because you already destructured them from the passed object (props) and therefore they are not available(defined) there anymore.
Hello guys I been looking in the internet trying to apply defaultProps to my components but nothing is working atm.
I will show you my code:
import styled from "styled-components";
const Button = styled.button`
text-transform: uppercase;
font-weight: bold;
font-size: 12px;
padding: 10px 20px;
border-radius: 5px;
border-style: none;
:focus {
outline: none;
}
${props =>
props.primary &&
`
background-color: ${props.theme.colors.primary};
color: ${props.theme.colors.blank};
:hover {
background-color: ${props.theme.colors.blank};
color: ${props.theme.colors.primary};
border-style: solid;
border-color: ${props.theme.colors.primary}
}
`}
${props =>
props.secondary &&
`
background-color: ${props.theme.colors.secondary};
color: ${props.theme.colors.blank};
:hover {
background-color: ${props.theme.colors.blank};
color: ${props.theme.colors.secondary};
border-style: solid;
border-color: ${props.theme.colors.secondary}
}
`}
${props =>
props.success &&
`
background-color: ${props.theme.colors.success};
color: ${props.theme.colors.blank};
:hover {
background-color: ${props.theme.colors.blank};
color: ${props.theme.colors.success};
border-style: solid;
border-color: ${props.theme.colors.success}
}
`}
${props =>
props.warning &&
`
background-color: ${props.theme.colors.warning};
color: ${props.theme.colors.blank};
:hover {
background-color: ${props.theme.colors.blank};
color: ${props.theme.colors.warning};
border-style: solid;
border-color: ${props.theme.colors.warning}
}
`}
`;
export default Button;
I just want to setup defaultProps to give some styled by default if I dont do for example:
<Button primary>Text</>
Here is another example, this is a bit different:
import React from "react";
import styled from "styled-components";
const Wrap = styled.input`
${props =>
props.primary &&
`
border: 2px ${props.theme.colors.primary} solid;
`}
${props =>
props.secondary &&
`
border: 2px ${props.theme.colors.secondary} solid;
`}
padding: 5px 10px;
background-color: transparent;
border-radius: 5px;
text-align: center;
:focus {
outline: none;
}
`;
const Input = ({
type,
onChange,
placeholder,
primary,
secondary,
className,
value,
name,
ref,
children
}) => {
return (
<Wrap
type={type}
onChange={onChange}
placeholder={placeholder}
primary={primary}
secondary={secondary}
value={value}
name={name}
ref={ref}
className={className}
>
{children}
</Wrap>
);
};
export default Input;
Any help will be useful, Im trying to make a Theme for myself as clean as possible. Thank you.
Adding defaultProps to components works out of the box, even with components created from Styled Components. You need to define the defaultProps on the component. Here's a complete example from a fresh create-react-app application:
import React from 'react';
import './App.css';
import styled from 'styled-components';
const ButtonBlue = styled.button`
background-color: ${props => props.actuallyMakeItGreen ? 'green' : 'blue'};
`;
ButtonBlue.defaultProps = {
actuallyMakeItGreen : true
}
function App() {
return (
<div className="App">
<ButtonBlue>Cool</ButtonBlue>
</div>
);
}
export default App;
Creates a button that looks like this:
import React from 'react';
import './App.css';
import styled from 'styled-components';
const ButtonBlue = styled.button`
background-color: ${props => props.actuallyMakeItGreen ? 'green' : 'blue'};
`;
function App() {
return (
<div className="App">
<ButtonBlue>Cool</ButtonBlue>
</div>
);
}
export default App;
The only thing changing here is inside the defaultProps property, where we default actuallyMakeItGreen to true rather than false.
First ensure you've passed your props into the styled component
<Button props={this.props} />
Then in your styled component you should be to format like so
const Button = styled.button`
${({ props }) => `
color: ${props.color};
`}
`
I want to run an animation using transition. The problem is I am using state to control it. So now, the components are created in render method. But every time the state is changed, the component is re-rendered. So how can I create the smaller components, so they are in scope, and I can use state to animate them?
import React, {Component, Fragment} from 'react';
import ArrowTemplate from "./ArrowTemplate";
import styled from 'styled-components';
class Accordion extends Component {
constructor(props) {
super(props);
this.state = {isAccordionExpanded: false};
this.toggleAccordion = this.toggleAccordion.bind(this);
}
toggleAccordion() {
this.setState({isAccordionExpanded: !this.state.isAccordionExpanded})
}
render() {
const {isAccordionExpanded} = this.state;
const AccordionSection = styled.div`
display: flex;
flex-direction: column;
`;
const AccordionBtn = styled.button`
background-color: #eee;
color: #444;
cursor: pointer;
padding: 18px;
display: flex;
align-items: center;
border: none;
outline: none;
transition: background-color 0.6s ease;
:hover,
:focus,
:active {
background-color: #ccc;
}
`;
const P = styled.p`
font-family: "Open Sans", sans-serif;
font-weight: 600;
font-size: 14px;
`;
const AccordionContent = styled.div`
background-color: white;
${isAccordionExpanded === true ? `height: 100px` : `height: 0`};
overflow: hidden;
transition: max-height 0.6s ease;
`;
const AccordionText = styled.div`
font-family: "Open Sans", sans-serif;
font-weight: 400;
font-size: 14px;
padding: 18px;
`;
return (
<AccordionSection>
<AccordionBtn
onClick={this.toggleAccordion}
>
<P>
<ArrowTemplate
color={"black"}
direction={"down"}
aria={"aria-roles: 'button'"}
onClick={this.toggleAccordion}
/>
</P>
</AccordionBtn>
<AccordionContent>
<AccordionText>
test
</AccordionText>
</AccordionContent>
</AccordionSection>
)
}
}
export default Accordion;
ArrowTemplate
import React from "react";
import BlackDownArrowSVG from './svgs/black-down-arrow.svg';
import WhiteDownArrowSVG from './svgs/white-down-arrow.svg';
import styled from 'styled-components';
import PropTypes from 'prop-types';
ArrowTemplate.propTypes = {
color: PropTypes.string.isRequired,
direction: PropTypes.string.isRequired,
styles: PropTypes.string,
aria: PropTypes.string.isRequired,
onClick: PropTypes.func.isRequired,
};
function ArrowTemplate(props) {
const {color, direction, styles, aria, onClick} = props;
const StyledArrowTemplate = styled.img.attrs({
src: color.toLowerCase() === "black" ? BlackDownArrowSVG : WhiteDownArrowSVG,
aria,
})`
${direction.toLowerCase() === "up" ? "transform: rotate(180deg);" : ""}
${styles}
`;
return <StyledArrowTemplate onClick={onClick}/>;
}
export default ArrowTemplate;
Try using
direction={this.state.isAccordionExpanded ? 'up' : 'down'}
for <ArrowTemplate />
I managed to do this by passing the properties (state) to a styled component like so:
<AccordionContent
ref={content}
isAccordionExpanded={isAccordionExpanded}
height={content.current === null ? '0' : content.current.scrollHeight}
>
const AccordionContent = styled.div`
max-height: ${({ isAccordionExpanded, height }) => (isAccordionExpanded ? height : '0')}px;
background-color: red;
overflow: hidden;
transition: max-height 0.7s;
`;
I have this code:
import React, {useState} from 'react';
import PropTypes from 'prop-types';
import styled from "styled-components";
import ArrowTemplate from "./ArrowTemplate";
const AccordionBtn = styled.button`
background-color: #eee;
color: #444;
cursor: pointer;
padding: 18px;
display: flex;
align-items: center;
border: none;
outline: none;
transition: background-color 0.6s ease;
:hover,
:focus,
:active {
background-color: #ccc;
}
`;
const AccordionTitle = styled.p`
font-family: "Open Sans", sans-serif;
font-weight: 600;
font-size: 14px;
`;
const AccordionContent = styled.div`
background-color: red;
overflow: hidden;
transition: 0.6s;
`;
const AccordionText = styled.div`
font-family: "Open Sans", sans-serif;
font-weight: 400;
font-size: 14px;
padding: 18px;
`;
const AccordionSection = styled.div`
display: flex;
flex-direction: column;
`;
Accordion.propTypes = {
title: PropTypes.string.isRequired,
content: PropTypes.node.isRequired,
id: PropTypes.string.isRequired,
};
function Accordion(props) {
const [isAccordionExpanded, setIsAccordionExpanded] = useState(false);
const toggleAccordion = () => {
setIsAccordionExpanded(!isAccordionExpanded);
};
return (
<AccordionSection>
<AccordionBtn onClick={toggleAccordion}>
<AccordionTitle>
{props.title}
</AccordionTitle>
<ArrowTemplate
color={'black'}
direction={isAccordionExpanded === true ? 'up' : 'down'}
onClick={toggleAccordion}
/>
</AccordionBtn>
<AccordionContent
style={{height: isAccordionExpanded === true ? "100px" : "0"}}
>
<AccordionText>
{props.content}
</AccordionText>
</AccordionContent>
</AccordionSection>
);
}
export default Accordion;
What this code does, is extends the accordeon on click. Preety simple. But now, I want to move this height:
<AccordionContent
style={{height: isAccordionExpanded === true ? "100px" : "0"}}
>
here:
const AccordionContent = styled.div`
background-color: red;
overflow: hidden;
transition: 0.6s;
`;
The problem is I need to use state, and if I declare it in the function, it will get re-rendered, and not run the animation. How can I pass the state to the styled-component?
You can just pass the isAccordionExpanded directly to the styled component. Change your style from this:
const AccordionContent = styled.div`
background-color: red;
overflow: hidden;
transition: 0.6s;
`;
to include this
height: ${({ isAccordionExpanded }) => (isAccordionExpanded ? "100px" : "0"};
Another way to do animation in React is using React Transition Group, Quite good