Styled Component not rendering when placed outside of component function - next.js

My styled component does not render when I place it outside of the 'Bubble' function. It renders when the styled components are declared within the 'Bubble' function but I then get an warning saying I shouldn't do that.
There are no errors that indicate what the problem is.
`
import styled from 'styled-components';
const Container = styled.div`
width: 0;
height: 0;
`;
const Inner = styled.div`
position: relative;
border-radius: 50%;
width: ${props => props.size};
height: ${props => props.size};
left: ${props => props.left};
top: ${props => props.left};
background: linear-gradient(180deg, #1A2132 0%, rgba(26, 33, 50, 0.1) 100%);
transform: rotate(${props => props.rotate}deg);
`;
export default function Bubble (props) {
return (
<Container>
<Inner
width={props.size}
height={props.size}
left={props.left}
top={props.top}
rotate={props.rotate}
/>
</Container>
)
}
`
Thank you!!

Related

How to make dropdown animation?

I am implementing drop-down list using styled-component in react. In the process, I have two questions.
First, when dropDownVisible changes from true to false, why doesn't the animation effect apply and it disappears immediately? How can I improve the animation effect? Like when this list goes down, I want to make it gradually when it goes up.
Second, when StyledDropdown is dropped down, I want it to drop down behind the StyledHead, so I set the z-index property like that. I want the StyledHead to be always on top, so I'm curious why the StyledHead is hidden as the StyledDropdown drops down, even though I gave the z-index property bigger.
The source code is roughly structured like this:
// AApage.jsx
import { useEffect, useState, useRef } from 'react';
import { MdArrowDropDown, MdArrowDropUp } from 'react-icons/md';
import styled, { keyframes } from 'styled-components';
const dropAnimation = keyframes`
0% {
transform : translateY(-300px);
display : none;
}
100% {
transform : translateY(0);
}
`;
const StyledHead = styled.div`
width: 100px;
height: 100px;
background-color: red;
z-index: 11;
`;
const StyledDropdown = styled.div`
width: 100px;
height: 300px;
background-color: #d9d9d9;
border-radius: 0px 0px 10px 10px;
z-index: 3;
animation: ${dropAnimation} 1s alternate;
`;
const AApage = () => {
const [dropDownVisible, setDropDownVisible] = useState<boolean>(false);
const toggleDropDownVisible = () => {
setDropDownVisible((prev) => !prev);
};
return (
<>
<StyledHead>
<div>Dropdown</div>
<span>{`${dropDownVisible}`}</span>
{dropDownVisible ? (
<MdArrowDropUp
onClick={() => {
toggleDropDownVisible();
}}
></MdArrowDropUp>
) : (
<MdArrowDropDown
onClick={() => {
toggleDropDownVisible();
}}
></MdArrowDropDown>
)}
</StyledHead>
{dropDownVisible ? (
<StyledDropdown>
<div>temp data</div>
<div>temp data</div>
<div>temp data</div>
</StyledDropdown>
) : (
<></>
)}
</>
);
};
export default AApage;

Reusable styled components (pseudo element) with logic

I've written some shared style to be used across different components, how can I change the value of left or width based a passed value or boolean logic so the values can be more dynamic?
And if possible, I don't want it passed as a prop in the actual component <bar left="20" />, but rather just within the declared styles.
const shared = css`
::after {
content: '';
left: 0;
width: 100%;
${(props) => props.beta &&
`
top: 0;
`
}
`
const foo = styled.div`
${shared}
`
const bar = styled.div`
${shared}
${child} {
${shared}
}
`
you can use a funtion instead:
const getShared = (props) => css`
::after {
content: '';
left: ${props.left || '0'};
width: ${props.width || '100%'};
${(otherProps) => otherProps.beta &&
`
top: 0;
`
}
`
const foo = styled.div`
${(props) => getShared(props)}
`
const bar = styled.div`
${(props) => getShared(props)}
${child} {
${(props) => getShared(props)}
}
`
if you want to simply override the shared css here is a simple exemple:
<div>
{/* this is a div that uses shared css */}
<div css={shared}>this is shared css</div>
{/* this is a div that uses shared css in his styling*/}
<FirstContainer>container extends shared css</FirstContainer>
{/* this is a div that uses shared css in his styling but overrides border color using a prop*/}
<SecondContainer borderColor="red">container overrriding the shared css</SecondContainer>
</div>
and here is the styling:
// this is the shared css
export const shared = css`
width: 100px;
height: 100px;
border: solid 1px green;
margin: 40px;
`
// div using the shared css
export const FirstContainer = styled.div`
${shared}
`
// div using the shared css but overriding border color
// props contains all the properties passed to the SecondContainer component (like left in bar component)
export const SecondContainer = styled.div`
${shared}
border-color: ${(props) => props.borderColor}
`
here is the result :

Understanding css helper function in styled components

Styled components has a helper css function. But I don't understand when should I used it.
For example this is their example where they use it:
import styled, { css } from 'styled-components'
const complexMixin = css`
color: ${props => (props.whiteColor ? 'white' : 'black')};
`
const StyledComp = styled.div`
/* This is an example of a nested interpolation */
${props => (props.complex ? complexMixin : 'color: blue;')};
`
But if we take similar example from docs here they don't use it:
const Button = styled.button`
/* Adapt the colors based on primary prop */
background: ${props => props.primary ? "palevioletred" : "white"};
color: ${props => props.primary ? "white" : "palevioletred"};
font-size: 1em;
margin: 1em;
padding: 0.25em 1em;
border: 2px solid palevioletred;
border-radius: 3px;
`;
Their description is also not clear and is confusing me:
A helper function to generate CSS from a template literal with
interpolations. You need to use this if you return a template literal
with functions inside an interpolation due to how tagged template
literals work in JavaScript.
Can someone help explain why we need it?
PS this answer also doesn't use it
I use the css function when I create variants for a component:
that is variant switcher:
const sizeVariant: Record<NonNullable<StyledLogoProps['size']>, ReturnType<typeof css>> = {
small: css`
width: 44px;
height: 44px;
`,
regular: css`
width: 93px;
height: 93px;
`,
};
that is component was created by 'styled-components':
interface StyledLogoProps {
size: 'small' | 'regular';
}
export const StyledLogo = styled.div<StyledLogoProps>`
${({ size }) => sizeVariant[size]}
`;
and this is the use in the react:
<>
<StyledLogo size="regular" />
<StyledLogo size="small" />
</>
quite a useful thing

Choppy height CSSTransition in react with multiple items

Goal: I'm getting really frustrated and have been scavenging through posts for hours now and can't find any real solution. I'm trying to animation a table row's height to expand/collapse when clicked on. I figured there should be an easy enough solution... Boy was I wrong.
Ideally since each row is going to store quite a bit of extra data, I'd like to load in the data, expand that single row, then remove the data when it's collapsed.
Problem:
I managed to get the animation working great!! I was so excited, only to find out that when I have more than ~3 rows, it gets extremely choppy/laggy. I can't find any fix what so ever.
Here is a sandbox https://codesandbox.io/s/0ql5vp13qv or if you wanted to see the code that manages the animation my code now:
import React, { Component } from 'react'
import { CSSTransition } from 'react-transition-group';
import Icon2 from '../Icon';
import * as Styled from './styles'
export default class CourseRow extends Component {
state = {switched: false};
selectCourse = () => {
this.setState(({switched}) => ({switched: !switched}));
}
render() {
return (
<Styled.Row onClick={this.selectCourse}>
<Styled.InnerRow>
<Styled.Field light>CSCI 1000</Styled.Field>
<Styled.Field>Computer Science 1</Styled.Field>
<Styled.Field>Explore algorithms and data structures that...</Styled.Field>
<Styled.Field><Styled.DropdownButton ><Icon2 icon="up_arrow"/></Styled.DropdownButton></Styled.Field>
</Styled.InnerRow>
<CSSTransition
classNames="fade"
timeout={300}
key={this.props.Title}
in={this.state.switched}
unmountOnExit
>
<div>
test<br/>test<br/>test<br/>
</div>
</CSSTransition>
</Styled.Row>
);
}
}
import styled from 'styled-components';
import Button from 'components/Button';
const columns = "1.5fr 2.5fr 5fr 3fr";
export const DropdownButton = styled(Button)`
background-color: blue;
`;
export const InnerRow = styled.div`
display: grid;
grid-template-columns: ${columns};
grid-column-gap: 1rem;
grid-row-gap: 0;
padding-top: ${props => props.heading ? '2.25rem' : '1.5rem'};
padding-bottom: ${props => props.heading ? '2rem' : '1.5rem'};
padding-left: 0.75rem;
padding-right: 0.75rem;
border-top: ${props => props.heading ? 'none' : '1px solid #E8E8E8'};
cursor: ${props => props.heading ? 'default' : 'pointer'};
`;
export const Row = styled.div`
&:hover {
background-color: #f7faff;
color: #1873EA;
}
& .fade-enter {
overflow-y: hidden;
max-height: 0;
}
& .fade-enter-active {
max-height: 200px;
transition: all 200ms ease;
}
& .fade-exit {
max-height: 200px;
}
& .fade-exit-active {
max-height: 0;
overflow-y: hidden;
transition: all 200ms ease;
}
`;
export const Field = styled.span`
display: flex;
align-items: center;
font-size: 14px;
font-weight: ${props => props.light ? '400' : '300'};
&:last-of-type {
justify-content: flex-end;
}
`;
I thought maybe adding key's to the elements/transitions would help however still nothing...
I took videos of the comparisons so you can see what I'm talking about it.
This is with 1 row:
https://www.youtube.com/watch?v=E6Db7nuqlgk&feature=youtu.be
This is with ~6 rows:
https://www.youtube.com/watch?v=Troba8eIqKA&feature=youtu.be

Can't get elements to stack

CSS isn't necessarily my strong suit but I have no idea why I can't get these two elements to stack? I set the parent position to relative and the child to absolute I also give the child a higher z-index but just can't get it to work. The <Icon /> is always offset to the right.
Code
import React from 'react';
import PropTypes from 'prop-types';
import styled from 'styled-components';
const propTypes = {
iconName: PropTypes.string,
color: PropTypes.string,
};
const defaultProps = {
iconName: 'add_box',
color: '#27B678',
};
const MaterialIcon = props => (
<i className={`material-icons ${props.className}`}>
{props.iconName.replace(/['"]+/g, '')}
</i>
);
const Icon = styled(MaterialIcon)`
color: ${props => props.color.replace(/['"]+/g, '')};
font-size: 36px;
position: absolute;
z-index: 10;
top: 10%;
left: 0;
right: 0;
bottom: 0;
`;
const Divider = props => (
<div
className="mx2"
style={{ position: 'relative', border: '1px solid #ececec' }}
>
<Icon
iconName={props.iconName}
color={props.color}
/>
</div>
);
Divider.propTypes = propTypes;
Divider.defaultProps = defaultProps;
export default Divider;
You need to use top and left to position the icon over the divider. You should give left a negative value equal to half the width of the icon so that it is centered over the divider. For instance, if the icon width is 50px, your Icon style should look like this:
const Icon = styled(MaterialIcon)`
color: ${props => props.color.replace(/['"]+/g, '')};
font-size: 36px;
position: absolute;
z-index: 1;
top: 10%;
left: -25px;
`;
Make sure to also give your divider a z-index of 0 so that the Icon appears on top of it.

Resources