Is it possible to style motion(framer-motion) icon in styled-components in React.
Here is my style.js file:
import { motion } from "framer-motion";
import { FaRegMoon } from "react-icons/fa";
export const MoonStyled = styled(motion.FaRegMoon)`
width: max-content;
height: max-content;
font-size: 40px;
`;
Here is my jsx file:
import { SunStyled } from "./styles/styles";
<SunStyled/>
I tried making it <motion.SunStyled/> but it doesn't work.
Is there anyway to get it worked?
Here is where the docs talk about this: https://www.framer.com/docs/component/#custom-components
This is the helpful statement that details how to forward a ref / make a custom component wrappable by motion:
const Component = React.forwardRef((props, ref) => (
<div ref={ref} />
))
const MotionComponent = motion(Component)
The icon component doesn't forward the ref to the actual dom svg, so that is why it is not wrappable by motion.
return (
<svg
stroke="currentColor"
fill="currentColor"
strokeWidth="0"
{...conf.attr}
{...attr}
{...svgProps}
className={className}
style={{ color: props.color || conf.color, ...conf.style, ...props.style}}
height={computedSize}
width={computedSize}
xmlns="http://www.w3.org/2000/svg"
>
{title && <title>{title}</title>}
{props.children}
</svg>
)
Even though they are spreading the props ref is the only prop that is not automatically passed.
source link
I wanted to test this on my own, so I made this example. It doesn't work for the above reason but feel free to see for yourself.
https://codesandbox.io/s/framer-motion-with-react-icons-rhqu6?file=/src/index.js
Related
i'm currently working on a project using stitches with cra but i've stuck to a problem with css props.
here's my code
Texts/index.tsx
import React from 'react';
import { TextStyle } from './textStyle';
const Texts = ({ text, css }: PropsType) => {
console.log(css);
return (
<>
<TextStyle css={{ ...css }} >
<>{text}</>
</TextStyle>
</>
);
};
export default Texts;
and this index.tsx is exported to another components
Container/index.tsx
import { styled, css } from '../../../stitches.config';
// atoms
import Texts from 'src/components/atoms/texts';
const PageContainer = () => {
return (
<Container>
<Contents >
<div>
<Texts
css={{ color: 'red' }}
/>
<Texts
css={{ paddingTop: '20px' }}
/>
</div>
</Contents>
</Container>
);
};
export default PageContainer;
as you can see with the above code, contains css as its child but css is never rendered at all
can anyone help me with this issue?
FYI, console.log(css); returned undefined to me.
Thank you in advance!
I'm new to gatsby and i'm trying to use gatsby background image plugin but it does not work, the image wont show on screen.
Here's my code :
import * as React from "react"
import { graphql, useStaticQuery } from 'gatsby'
import { createGlobalStyle } from "styled-components"
import BackgroundImage from 'gatsby-background-image'
const GlobalStyle = createGlobalStyle`
body{
background-color: #270A63;
margin : 0px;
display:flex;
}`
const Layout = (props, { children }) => {
const data = useStaticQuery(
graphql`
query {
bgImage : file(relativePath: {eq: "background.png"}) {
childImageSharp {
gatsbyImageData(quality: 90)
}
}
}
`
)
const imageData = data.bgImage.childImageSharp.gatsbyImageData;
return (
<React.Fragment>
<GlobalStyle />
<BackgroundImage
Tag="section"
image={imageData}
>
</BackgroundImage>
</React.Fragment>
)
}
export default Layout
Layout is a custom component that I'm using in index page.
I used console.log to check imageData and it is an object that looks like this :
{bgImage:
childImageSharp:
gatsbyImageData:
backgroundColor: "#680818"
height: 1117
images:
fallback: {src: '/static/32d467ee3060062ab794e34f2002c807/f89cf/background.png', srcSet: '/static/32d467ee3060062ab794e34f2002c807/5829e/bac…60062ab794e34f2002c807/f89cf/background.png 1010w', sizes: '(min-width: 1010px) 1010px, 100vw'}
sources: [{…}]
[[Prototype]]: Object
layout: "constrained"
width: 1010}
I don't understand why it does not work.
Thank you for your help !
As per your GraphQL, you are using a Gatsby version greater or equal than 3. I think your snippet should look like something like:
import React from 'react'
import { graphql, useStaticQuery } from 'gatsby'
import { getImage, GatsbyImage } from "gatsby-plugin-image"
import { convertToBgImage } from "gbimage-bridge"
import BackgroundImage from 'gatsby-background-image'
const GbiBridged = () => {
const { bgImage }= useStaticQuery(
graphql`
query {
bgImage : file(relativePath: {eq: "background.png"}) {
childImageSharp {
gatsbyImageData(quality: 90)
}
}
}
`
)
const image = getImage(bgImage)
const backgroundImage= convertToBgImage(image)
return (
<React.Fragment>
<GlobalStyle />
<BackgroundImage
Tag="section"
{...backgroundImage}
preserveStackingContext
>
<div style={{minHeight: 1000, minWidth: 1000}}>
<GatsbyImage image={image} alt={"testimage"}/>
</div>
</BackgroundImage>
</React.Fragment>
)
}
export default GbiBridged
Modified from: https://www.gatsbyjs.com/plugins/gatsby-background-image/#gatsby-34--gatsby-plugin-image applying your code
Gatsby changed the image plugin from gatsby-image (Gatsby 1 and 2) to gatsby-plugin-image (version 3 onwards). Among other things, it has changed the internal GraphQL nodes of the image data, hence the workaround of using gatsby-background-image has also changed accordingly. In your case, you are using the deprecated version of gatsby-image so your code is not able to display the image.
You can follow the full discussion in this GitHub thread: https://github.com/timhagn/gatsby-background-image/issues/141
I'd recommend not using any external plugins for this but using CSS to achieve this. This way you don't have to learn any new third-party plugins and can use the knowledge you have about CSS. Here's an example from the docs: https://www.gatsbyjs.com/docs/how-to/images-and-media/using-gatsby-plugin-image/#background-images
import * as React from "react"
import { StaticImage } from "gatsby-plugin-image"
export function Hero() {
return (
<div style={{ display: "grid" }}>
{/* You can use a GatsbyImage component if the image is dynamic */}
<StaticImage
style={{
gridArea: "1/1",
// You can set a maximum height for the image, if you wish.
// maxHeight: 600,
}}
layout="fullWidth"
// You can optionally force an aspect ratio for the generated image
aspectRatio={3 / 1}
// This is a presentational image, so the alt should be an empty string
alt=""
// Assisi, Perúgia, Itália by Bernardo Ferrari, via Unsplash
src={
"https://images.unsplash.com/photo-1604975999044-188783d54fb3?w=2589"
}
formats={["auto", "webp", "avif"]}
/>
<div
style={{
// By using the same grid area for both, they are stacked on top of each other
gridArea: "1/1",
position: "relative",
// This centers the other elements inside the hero component
placeItems: "center",
display: "grid",
}}
>
{/* Any content here will be centered in the component */}
<h1>Hero text</h1>
</div>
</div>
)
}
I want to create a custom material ui icon from a svg file with two paths.
My code using
import React from 'react';
import { makeStyles } from '#material-ui/core/styles';
import { green } from '#material-ui/core/colors';
import SvgIcon from '#material-ui/core/SvgIcon';
const useStyles = makeStyles((theme) => ({
root: {
'& > svg': {
margin: theme.spacing(2),
},
},
}));
function GradIcon(props) {
return (
<SvgIcon {...props}>
<path
d="M142.45,174.613c-4.645,0-11.495-0.514-17.779-2.926l-50.271-19.366H49.774v30.162c0,9.274,6.9,19.802,15.405,23.499
l60.872,26.496c8.505,3.691,22.312,3.707,30.826,0.036l61.536-26.574c8.508-3.671,15.41-14.183,15.41-23.457v-30.162h-27.175
l-44.547,18.78C156.742,173.365,149.756,174.613,142.45,174.613z"
/>
<path
d="M6.475,112.944l121.222,46.709c8.661,3.329,22.603,3.112,31.152-0.492l115.768-48.801v71.999l-7.151,23.866h20.682
l-7.399-24.114V107.45h-0.208c4.997-3.449,3.832-7.747-3.567-10.393L159.196,55.146c-8.74-3.117-22.859-2.985-31.545,0.277
L6.529,100.99C-2.157,104.258-2.178,109.612,6.475,112.944z"
/>
</SvgIcon>
);
}
export default function SvgIconsColor() {
const classes = useStyles();
return (
<div className={classes.root}>
<GradIcon />
</div>
);
}
like in the docs didn't work out. As I am fairly new to javascript and react I thought I'd ask on here.
Thanks
I solved it by creating a separate component with the following Layout like in this tutorial:
First I converted the image online to an svg.
Then I opened it within an editor and selected the whole svg part.
This part is posted within the component like below. Be sure to disable any unnecessary properties, and set the width and height to 24. The properties below should be enough. Don't delete parts. Just comment out and try till it fits your desired output.
import React from "react";
const IconName = () => {
return (
<svg xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
version="1.1"
viewBox="<viewBox>"
<path d="<path>"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
fill="<color>"
fill-rule="evenodd"
/>
</svg>
);
};
export default IconName;
Then just import the icon to the component you need it in.
The number of paths doesn't matter, just remember to include all the properties after the path.
no matter what I do, I can't change color of these 2 react icons, I am not sure if they are set to be not changeable. I used other icons before, haven't had this issue yet, Thank you!
import React from "react";
import "./styles.css";
import { GrSubtractCircle, GrAddCircle } from "react-icons/gr";
export default function App() {
return (
<div className="App">
<GrAddCircle id="try"/>
</div>
);
}
css
#try{
color: green;
}
svg{
color: aqua;
}
There is a problem with the stroke attribute in path in svg its defaulted to "#000" which means it will always be black color it should be "currentColor"
as a work around this problem with this particular element in this library
i did the following
import React from "react";
import { GrAddCircle } from "./Icons";
function App() {
return (
<div className="App">
<GrAddCircle
color="red"
title="folder icon"
className="additional-class-name"
/>
</div>
);
}
export default App;
then in src i created folder called Icons to work as my own custom Icons
then inside the folder i created index.js
import React from "react";
export const GrAddCircle = ({ color, size, title, className }) => {
return (
<svg
stroke="currentColor"
fill="currentColor"
strokeWidth="0"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
height={ size ? size : "1rem" }
width={ size ? size : "1rem" }
style={{ color }}
className={ className ? className : '' }
>
{ title ? <title>{title}</title> : null }
<path
fill="none"
stroke="currentColor"
strokeWidth="2"
d="M12,22 C17.5228475,22 22,17.5228475 22,12 C22,6.4771525 17.5228475,2 12,2 C6.4771525,2 2,6.4771525 2,12 C2,17.5228475 6.4771525,22 12,22 Z M12,18 L12,6 M6,12 L18,12"
></path>
</svg>
);
};
this way you can create your own custom icons based on react-icons and import it from Icons frolder directly
now the element will have the property size (width, height attributes), title, className and color. you can add more custom props if you want.
I'm playing around with styled-components and trying to create a svg circle spinner component. Everything is great except when I try to use the component multiple times in same page then every component is using the same strokeColor from the last one. The other props strokeWidth is working fine though.
import React from "react";
import ReactDOM from "react-dom";
import Spinner from "./Spinner";
import "./styles.css";
function App() {
return (
<div className="App">
<Spinner strokeColor="#000000" strokeWidth={2} />
<Spinner strokeColor="red" strokeWidth={1} />
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
What am I missing here?
Here's the codesandbox demo link: https://codesandbox.io/s/pyo8kox787
The problem I see is that you've created your keyframes as regular css and not with styled-components keyframes helper.
From the styled-components docs:
CSS animations with #keyframes aren't scoped to a single component but
you still don't want them to be global to avoid name collisions. This
is why we export a keyframes helper which will generate a unique
instance that you can use throughout your app
As for what I can tell, the keyframes is created for the last component being rendered as they aren't scoped to the component.
The fix is using the keyframes helper like this:
import styled, {keyframes} from "styled-components";
const colorKeyFrames = keyframes`
0% {
stroke: ${props => props.color || "#ffffff"};
}
40% {
stroke: ${props => props.color || "#ffffff"};
}
66% {
stroke: ${props => props.color || "#ffffff"};
}
80%,
90% {
stroke: ${props => props.color || "#ffffff"};
}
`;
And a fix for your sandbox here.
Keep in mind, you'll need to fix it for every keyframes you have there.