Styled component not being respected between files? - css

For whatever reason, the buttons (defined by AboutItem) are displaying light blue backgrounds when I hover over them. I want to make it #282828.
In a separate file I define some styled components for Buttons:
export const Button = styled.button`
display: inline-block;
font-size: 1em;
margin: 1em;
padding: 0em 1em;
`;
export const InfoButton = styled(Button)`
color: grey;
&:hover {
background-color: lightblue;
}
`;
which I then use:
interface AboutNavProps {
selected: boolean;
}
const AboutItem = styled(InfoButton) <AboutNavProps>`
color: grey;
background-color: ${props => props.selected ? "#282828" : "transparent"};
text-align: center;
&:hover {
background-color: #282828;
}
`;
export function AboutNavbar() {
const router = useRouter()
useEffect(() => {
router.prefetch("/method");
}, [])
return (
<AboutNav aria-label="Navbar">
<AboutItem as="a" href="method" selected={router.pathname == "/method"}>How It Works</AboutItem>
<AboutItem as="a" href="about" selected={router.pathname == "/about"}>About</AboutItem>
<Logo />
</AboutNav>
);
}
Is there a reason for this? I don't understand why the light blue overrides the color I define for the hover.

Related

update properties of style component using switch statement

I know there's a similar question but what I need is different.
I have declared the common styles that my button will be using and I'm using a function with a switch statement that has different properies for different buttons that I will be using in other pages and for one case I need the border-radius and padding different from the common one, how can I update(or replace) the value without using !important or && {.
Here's the code
import { TTheme } from 'src/styles/Themes/Theme';
import styled, { css, FlattenSimpleInterpolation } from 'styled-components';
const getVariantCSS = <T extends TTheme>(props: T): FlattenSimpleInterpolation => {
const { theme } = props;
switch (props.variant) {
case 'secondary':
return css`
background-color: ${theme.colors.white};
color: ${theme.colors.primary};
border: ${theme.borders.solid1} ${theme.colors.primary};
&:hover {
color: ${theme.colors.white};
background-color: ${theme.colors.shades.hoverLight};
border: ${theme.borders.none};
box-shadow: ${theme.boxShadows.primary};
}
`;
case 'half':
return css`
color: ${theme.colors.white};
background-color: ${theme.colors.primary};
&& {
border-radius: ${theme.radius.half};
padding: ${theme.paddings.small};
}
border: ${theme.borders.solid2} ${theme.colors.white};
`;
case 'dark':
return css`
background-color: ${theme.colors.tertiary};
color: ${theme.colors.primary};
border: ${theme.borders.solid1} ${theme.colors.primary};
&:hover {
color: ${theme.colors.white};
background-color: ${theme.colors.shades.hoverDark};
box-shadow: ${theme.boxShadows.primary};
filter: ${theme.filter.brightness};
border: ${theme.borders.none};
opacity: ${theme.opacity.default};
}
`;
default:
return css`
background-color: ${theme.colors.primary};
color: ${theme.colors.white};
border: ${theme.borders.none};
box-shadow: ${theme.boxShadows.primary};
&:hover {
color: ${theme.colors.white};
background-color: ${theme.colors.shades.hoverLight};
}
`;
}
};
export const StyledButton = styled.button`
${getVariantCSS}
width: 100%;
height: 100%;
padding: ${(props) => props.theme.paddings.medium};
display: ${(props) => props.theme.content.display.flex};
flex-direction: ${(props) => props.theme.content.flexDirection.row};
justify-content: ${(props) => props.theme.content.justifyContent.center};
align-items: ${(props) => props.theme.content.alignItems.center};
flex-grow: ${(props) => props.theme.content.flexGrow.one};
border-radius: ${(props) => props.theme.radius.button};
I suggest using the cascade. just place "getVariantsCSS" below the main styles and then the desired styles will be applied and then "important" and "&&" is not needed.
https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Cascade_and_inheritance#the_cascade
export const StyledButton = styled.button`
width: 100%;
height: 100%;
padding: ${(props) => props.theme.paddings.medium};
display: ${(props) => props.theme.content.display.flex};
flex-direction: ${(props) => props.theme.content.flexDirection.row};
justify-content: ${(props) => props.theme.content.justifyContent.center};
align-items: ${(props) => props.theme.content.alignItems.center};
flex-grow: ${(props) => props.theme.content.flexGrow.one};
border-radius: ${(props) => props.theme.radius.button};
${getVariantCSS}
`

How to change CSS of a child component from parent component

I have a react component called TeamBanner like so
import styles from "./teamBanner.module.css";
import { useNavigate } from "react-router-dom";
import { TeamBannerProps } from "../ProjectTypes.types";
export const TeamBanner = ({
team,
onBannerClick,
showName,
}: TeamBannerProps) => {
let navigate = useNavigate();
const handleOnClick = () => {
navigate(`/${team}`);
onBannerClick();
};
return (
<div
className={`${styles.container} flex theme-light ${
showName ? "" : styles["no-name"]
}`}
title={team}
onClick={handleOnClick}
>
<div>
<img
src={require(`../logos/${team}.svg`)}
alt="logo"
className={`${styles.logo} ${showName ? "" : styles["only-logo"]}`}
/>
</div>
{showName ? team : ""}
</div>
);
};
The teamBanner.module.css file is like so
.container {
margin: 0.25em;
align-items: center;
cursor: pointer;
top: 0;
z-index: 2;
background-color: hsl(var(--color-background));
padding: 0.1em 0.25em;
border-radius: 0.5em;
box-shadow: 0.05rem 0.05rem 0.2rem rgb(0 0 0 / 50%);
font-family: var(--ff-serif);
font-size: var(--fs-200);
}
.logo {
display: inline-block;
vertical-align: middle;
width: 3vmax;
height: 3vmax;
}
.container:hover {
outline: 0.15em solid hsl(240, 90%, 67%);
}
.no-name {
border-radius: 0.25em;
}
.only-logo {
width: 5vmax;
height: 5vmax;
}
I am using it to create a list of team of a page & this works just fine.
However, I want to use it in another place also. In the place, the to now want the .container:hover effect & I want the font properties of the .contaner and width & height properties of the .logo changed.
How can I accomplish this? only changing these items of the module.css? Can any one help? Thanks

I want to reuse certain CSS properties in Emotion/styled component

import styled from '#emotion/styled';
type ColorProps = {
Coloured: boolean,
}
const BoxStyled = styled.div`
${(props:ColorProps) =>
props.Coloured ? {
background: "#304f8f",
border: "1.85px solid #304f8f",
color: "white",
width: "4rem",
height: "2.5rem",
padding:"0 11px"
} :
{
border: "1.98px solid #2c8090",
width: "4rem",
height: "2.5rem",
padding:"0 11px"
}
}`
here in BoxStyled I don't want to write width: "4rem", height: "2.5rem", padding:"0 11px" twice how do I achieve this ?
Use css to make a variable of style.
import { css } from 'styled-components'
const reuse = css`
width: 4rem;
height: 2.5rem;
padding: 0 11px;
`
const StyleA = styled.div`
background-color: black;
${reuse}
`
const StyleB = styled.div`
background-color: red;
${reuse}
`
Check this for more information.
You can define the main style and when needed to change overwrite new style.
import styled from '#emotion/styled';
type ColorProps = {
Coloured: boolean,
}
const BoxStyled = styled.div`
border: "1.98px solid #2c8090",
width: "4rem",
height: "2.5rem",
padding:"0 11px"
${(props:ColorProps) =>
props.Coloured && {
background: "#304f8f",
border: "1.85px solid #304f8f",
color: "white",
}
}`

How to style multiple variations of a <button> with Styled Components

I have a simple colored button in my app that needs to change color based on some UI state:
const StyledButton = styled.button`
& {
border: 0;
color: white;
cursor: pointer;
}
&:hover {
background-color: ${(props) => props.theme.hoverColor};
}
&.base {
background-color: ${(props) => props.theme.baseColor};
}
&.selected {
background-color: ${(props) => props.theme.selectedColor};
}
&&.danger:hover {
background-color: ${(props) => props.theme.dangerColor};
}
&.disabled {
background-color: ${(props) => props.theme.disabledColor};
}
`;
Previously I was using CSS Modules to make sure classes would not "leak" to other styles and I have obtained the styled component by essentially a 1-to-1 translation.
.Button {
border: 0;
color: white;
cursor: pointer;
}
.Button:hover {
background-color: var(--hover-color);
}
.Button.base {
background-color: var(--base-color);
}
.Button.selected {
background-color: var(--selected-color);
}
.Button.Button.danger:hover {
background-color: var(--danger-color);
}
.Button.disabled {
background-color: var(--disabled-color);
}
I like the theming support in Styled Components, but I dislike how now my "local" classes are no longer local to the component. I consider this a significant tradeoff.
Am I missing the correct way of implementing multiple variants of a component?
At the moment I have found two solutions:
The first is to calculate by hand the end result and avoid any classes
const StyledButton = styled.button`
& {
border: 0;
color: white;
cursor: pointer;
}
${(props) =>
props.isBase &&
css`
&,
&:hover {
background-color: ${(props) => props.theme.baseColor};
}
`}
${(props) =>
props.selectedColor &&
css`
&,
&:hover {
background-color: ${(props) => props.theme.selectedColor};
}
`}
${(props) =>
props.isDisabled &&
css`
&,
&:hover {
background-color: ${(props) => props.theme.disabledColor};
}
`}
${(props) =>
props.isDanger &&
css`
& {
background-color: ${(props) => props.theme.dangerColor};
}
&:hover {
background-color: ${(props) => props.theme.dangerColor};
}
`}
`;
which works but is quite ugly
and the other is to split the StyledButton into many components:
const StyledButton = styled.button`
& {
border: 0;
color: white;
cursor: pointer;
background-color: ${(props) => props.theme.baseColor};
}
`;
const StyledSelectedButton = styled(StyledButton)`
& {
background-color: ${(props) => props.theme.selectedColor};
}
`;
const StyledDisabledButton = styled(StyledButton)`
& {
background-color: ${(props) => props.theme.disabledColor};
}
`;
const StyledDangerButton = styled(StyledButton)`
& {
background-color: ${(props) => props.theme.baseColorColor};
}
&&:hover {
background-color: ${(props) => props.theme.dangerColor};
}
`;
Which is better but I am afraid of an eventual combinatorial explosion once more complex states are involved (a selected danger component) or more pseudoclasses are involved.
Moreover if the button in question had a state (e.g. a click counter) changing style would destroy the state.
I cannot think of a solution around this problem.

onClick() not working on several viewports

I am trying to make a portfolio for my student organization and am using the package react-flip-card for profiles of the team members in that organization. Interestingly enough, when I viewed in on my iPad Pro, on landscape view (width > 1024px), I was able to trigger the flip animation by pressing the button. But when I was on portrait view (width: 1024px), suddenly the flip card will not trigger.
You can access my website and try it:
https://ibsa-display-sub.herokuapp.com/about
Here is my code:
PeopleCard.js
import React, {Component} from 'react'
import styled from 'styled-components'
import {mediaQueries, colors} from '../../shared/config'
import ReactCardFlip from 'react-card-flip'
import overlay from '../../images/overlay.png'
// width change for officers in about us
const FrontContainer = styled.div`
box-shadow: 15px 15px 5px;
background-color: white;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
${mediaQueries.tablet} {
box-shadow: 7.5px 7.5px 3.725px;
}
`
const BackContainer = styled.div`
box-shadow: 10px 10px 5px;
border-radius:1em;
height: ${props => `${props.cardHeight}px`};
background-image: url(${props => props.overlay}), url(${props => props.imgURL});
background-position: center top;
background-size: cover;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
${mediaQueries.tablet} {
box-shadow: 7.5px 7.5px 3.725px;
}
`
const Image = styled.img`
/* border-top-left-radius: 1em;
border-top-right-radius: 1em;
border-bottom: 1px solid black; */
`;
const Description = styled.div`
text-align: center;
margin: 1em 0.5em;
`;
const Name = styled.h2`
font-weight: 800;
font-size: 2em;
margin-bottom: 0;
`;
const Title = styled.h4`
font-weight: 300;
`
const Button = styled.button`
border-radius:1em;
margin-bottom: ${props => props.side === "front" ? "1em" : "0"};
margin-top: ${props => props.side === "back" ? "1em" : "0"};
cursor: pointer;
height: 3em;
background-color: ${colors.blue};
${mediaQueries.iphone7} {
padding: 0.5em 2em;
}
`;
const Summary = styled.p`
margin: 1em 2.5em;
font-weight: 400;
text-align: justify;
color: ${colors.white};
font-weight: 400;
`;
export default class PeopleCard extends Component {
constructor() {
super();
this.imgref = React.createRef();
this.frontContainer = React.createRef();;
this.state = {
isFlipped: false,
cardHeight : 0,
};
this.handleClick = this.handleClick.bind(this);
this.updateHeight = this.updateHeight.bind(this);
}
/**
* handles the flip card animation for people card
*/
handleClick(e) {
e.preventDefault();
this.setState(prevState => ({ isFlipped: !prevState.isFlipped }));
}
componentDidMount() {
this.updateHeight();
window.addEventListener("resize", this.updateHeight);
}
componentWillUnmount() {
window.removeEventListener("resize", this.updateHeight);
}
/**
* updateHeight() updates the height of the container for the front side
* of the car whenever it's changed. The height is then used for BackContainer
* to have reference to (passed in as a prop), so that size is consistent
*/
updateHeight() {
this.setState({ cardHeight: this.frontContainer.current.clientHeight })
}
render() {
const {imgURL, name, title, bio, instalink, lilink} = this.props;
const {cardHeight} = this.state;
return (
<ReactCardFlip
className="card-container"
isFlipped={this.state.isFlipped}
flipDirection="horizontal"
infinite="true"
>
<FrontContainer ref={this.frontContainer}
id="get-height">
<Image
src={imgURL}
ref={this.imgref}
onLoad={() => {
if (cardHeight < 400) {
this.setState({
cardHeight: cardHeight + this.imgref.current.clientHeight
})
}
}}
className="img-fluid"
/>
<Description >
<Name className="heading"> {name} </Name>
<Title> {title} </Title>
</Description>
<Button side="front" onClick={this.handleClick}> Learn more </Button>
</FrontContainer>
<BackContainer
cardHeight={cardHeight}
overlay={overlay}
imgURL={imgURL}
>
<Summary>
{bio}
</Summary>
<Button side="back" onClick={this.handleClick}>Back</Button>
</BackContainer>
</ReactCardFlip>
)
}
}
config.js
export const colors = {
blue : "#1F8AD0",
white: "#ffffff",
lightblue: "#A0CAEA",
}
export const mediaQueries = {
iphone7: "#media screen and (max-width: 480px)",
notIphone7: "#media screen and (min-width: 481px)",
beforeMobile : "#media screen and (min-width: 481px) and (max-width: 700px)",
mobile: "#media screen and (max-width: 700px)",
notMobile: "#media screen and (min-width: 701px)",
notTablet: "#media screen and (min-width: 1024px)",
tablet: "#media screen and (max-width: 1024px)",
};
EDIT: SOLVED! it turns out it has something to do with a z-index that made the buttons and forms unclickable.

Resources