Why doesn't svg file work in react-native? - reactjs

I dont have any error, but it doesnt work.
I have a Search bar on the screen. Before the placeholder, i want to show a search icon there. As I know, I did what i needed to get this worked. I installed npm install react-native-svg --save and npm install react-native-svg-transformer --save And I added new code into metro.config.js But there must be something missing as it doesnt work.
Here is App.js
import React from 'react';
import { StyleSheet, Text, View, TextInput } from 'react-native';
import Search from "./src/icons/search.svg";
const App = () => {
return (
<View style={styles.container}>
<View style={styles.firstPart}>
<Text style={styles.date}>Saturday, Feb 21</Text>
<View style={styles.package}>
<Text style={styles.packageText}>Your Package</Text>
<View style={styles.plusIcon}>
<Text style={styles.textPlus}>+</Text>
</View>
<Search width={120} height={40} />
</View>
<TextInput style={styles.input} placeholder="Search" placeholderTextColor="gray"></TextInput>
</View>
</View>
);
};
const styles = StyleSheet.create({
container:{
margin:10,
},
firstPart:{
backgroundColor: "mediumblue",
borderTopRightRadius:40,
borderTopLeftRadius:40,
padding:20,
},
date:{
fontSize:15,
color:"white",
},
package:{
flexDirection: "row",
justifyContent: "space-between",
},
packageText: {
fontSize:25,
color:"white",
flexDirection: "column",
},
plusIcon: {
height:25,
width:25,
borderRadius:25,
backgroundColor:"blue",
marginTop:5,
},
textPlus: {
fontSize:25,
fontWeight:"bold",
color:"white",
marginLeft:5,
},
input: {
height:40,
borderWidth:.5,
borderRadius:10,
marginVertical:10,
}
});
export default App;
metro.config.js
/**
* Metro configuration for React Native
* https://github.com/facebook/react-native
*
* #format
*/
module.exports = {
transformer: {
getTransformOptions: async () => ({
transform: {
experimentalImportSupport: false,
inlineRequires: true,
},
}),
},
};
const { getDefaultConfig } = require("metro-config");
module.exports = (async () => {
const {
resolver: { sourceExts, assetExts }
} = await getDefaultConfig();
return {
transformer: {
babelTransformerPath: require.resolve("react-native-svg-transformer")
},
resolver: {
assetExts: assetExts.filter(ext => ext !== "svg"),
sourceExts: [...sourceExts, "svg"]
}
};
})();
src/icons/search.svg
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<g>
<g>
<path d="M310,190c-5.52,0-10,4.48-10,10s4.48,10,10,10c5.52,0,10-4.48,10-10S315.52,190,310,190z"/>
</g>
</g>
<g>
<g>
<path d="M500.281,443.719l-133.48-133.48C388.546,277.485,400,239.555,400,200C400,89.72,310.28,0,200,0S0,89.72,0,200
s89.72,200,200,200c39.556,0,77.486-11.455,110.239-33.198l36.895,36.895c0.005,0.005,0.01,0.01,0.016,0.016l96.568,96.568
C451.276,507.838,461.319,512,472,512c10.681,0,20.724-4.162,28.278-11.716C507.837,492.731,512,482.687,512,472
S507.837,451.269,500.281,443.719z M305.536,345.727c0,0.001-0.001,0.001-0.002,0.002C274.667,368.149,238.175,380,200,380
c-99.252,0-180-80.748-180-180S100.748,20,200,20s180,80.748,180,180c0,38.175-11.851,74.667-34.272,105.535
C334.511,320.988,320.989,334.511,305.536,345.727z M326.516,354.793c10.35-8.467,19.811-17.928,28.277-28.277l28.371,28.371
c-8.628,10.183-18.094,19.65-28.277,28.277L326.516,354.793z M486.139,486.139c-3.78,3.78-8.801,5.861-14.139,5.861
s-10.359-2.081-14.139-5.861l-88.795-88.795c10.127-8.691,19.587-18.15,28.277-28.277l88.798,88.798
C489.919,461.639,492,466.658,492,472C492,477.342,489.919,482.361,486.139,486.139z"/>
</g>
</g>
<g>
<g>
<path d="M200,40c-88.225,0-160,71.775-160,160s71.775,160,160,160s160-71.775,160-160S288.225,40,200,40z M200,340
c-77.196,0-140-62.804-140-140S122.804,60,200,60s140,62.804,140,140S277.196,340,200,340z"/>
</g>
</g>
<g>
<g>
<path d="M312.065,157.073c-8.611-22.412-23.604-41.574-43.36-55.413C248.479,87.49,224.721,80,200,80c-5.522,0-10,4.478-10,10
c0,5.522,4.478,10,10,10c41.099,0,78.631,25.818,93.396,64.247c1.528,3.976,5.317,6.416,9.337,6.416
c1.192,0,2.405-0.215,3.584-0.668C311.472,168.014,314.046,162.229,312.065,157.073z"/>
</g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

I just used your svg file to see if it works and it is visible only if you set a fill property to it.
Like this
<Search width={120} height={40} fill={"#00FF00"}/>
// Putting the icon inside text field; sorry for the inline styling
<View
style={{position: 'absolute', top: 10, zIndex: 20}}
>
<Search height={30} width={30} fill={"#00FF00"}/>
</View>
<TextInput
style={{backgroundColor: 'orange', height: 50, paddingLeft: 50}} placeholder="Search" placeholderTextColor="gray"
/>
// You will have to change that top style in accordance to your layout of course
EDIT
As per my knowledge, that placeholder can only be a string. But anyway, you can obtain what you've said. You can have a state called, let's say isTextInputFocused which will become true when textInput is focused and false when it is blurred (implement onFocus & onBlur to change that state) and then,
{ !isTextInputFocused && ( <View
style={{position: 'absolute', top: 10, zIndex: 20}}
>
<Search height={30} width={30} fill={"#00FF00"}/>
</View> )}
Basically, conditionally display that image by a variable you manipulate

Related

Apply fill color to all circles in an SVG in React

I'm trying to use React to work with SVG's in a procedural manner.
Something I'd like to do is use a parent element to set the color of different circles in my svg:
const MySVG = (): JSX.Element => {
return (
//all circles in this SVG should have a yellow fill
<svg
version="1.1"
xmlns="http://www.w3.org/2000/svg"
x="0px"
y="0px"
style={{ width: "fit-content", height: "100%" }}
viewBox="0 0 971 191"
>
<SVGProcessor>
<circle cx="730.9" cy="109.6" r="52.9" />
<g>
<path d="M587.8,39.6c10.7,8,25.9,5.9,33.9-4.8L641.9,91c-13-3.1-26.1,4.9-29.2,17.9L587.8,39.6z" />
</g>
<circle cx="816.2" cy="53.9" r="33.4" />
<g>
<circle cx="547.5" cy="93.1" r="67" />
</g>
<circle cx="915.5" cy="95.5" r="55" />
</SVGProcessor>
</svg>
);
};
//should apply a yellow fill to all circles in the svg
const SVGProcessor = ({
children,
}: {
children: JSX.Element[];
}): JSX.Element => {
useEffect(() => {
children.forEach((child) => {
if (child.type.displayName === "circle") {
const c = child as React.SVGProps<SVGCircleElement>;
c.fill = "yellow"
}
});
}, []);
return <>{children}</>;
};
But this doesn't work with nested svg elements, as they are not direct children of the wrapper component.
Is there a good way to compose SVG's procedurally?

Selectable states in react-simple-maps

I'm creating a map using react-simple-maps librery
this is my code so far
<ComposableMap
style={{ backgroundColor: "white", }}
projection="geoAlbers"
fill={'rgb(185,185,185)'}
projectionConfig={{
center:[-5, 25]
}}>
<Geographies style={{backgroundColor:'green', bottom:100}} geography={geoUrl}>
{({ geographies }) =>
geographies.map(geo => (
<Geography key={geo.rsmKey} geography={geo} />
))
}
</Geographies>
<Marker coordinates={[-100.460846,25.649345]}>
<g
fill="none"
stroke="#003DA5"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
transform="translate(-12, -24)"
>
<circle cx="12" cy="10" r="3" />
<path d="M12 21.7C17.3 17 20 13 20 10a8 8 0 1 0-16 0c0 3 2.7 6.9 8 11.7z" />
</g>
</Marker>
</ComposableMap>
but is there any way to get rid off of this border when you select a state ?
You can do that, passing the style attribute on <Geography />.
<ComposableMap>
<Geographies geography={geoUrl}>
{({ geographies }) =>
geographies.map(geo => <Geography style={{
default: { outline: "none" },
hover: { outline: "none" },
pressed: { outline: "none" },
}} key={geo.rsmKey} geography={geo} />)
}
</Geographies>
</ComposableMap>

How to make a line break in svg

I have the following SVG of dynamically rendered pie chart using react-minimal-pie-chart :-
<svg viewBox="0 0 100 100" width="100%" height="100%"><path d="M 75 50 A 25 25 0 0 1 54.34120444167326 74.6201938253052" fill="none" stroke-width="50" stroke="#8dcd81"><title>Excellent</title></path><path d="M 54.34120444167326 74.6201938253052 A 25 25 0 0 1 26.507684480352285 41.449496416858295" fill="none" stroke-width="50" stroke="#eefa6b"><title>Good</title></path><path d="M 26.507684480352285 41.449496416858295 A 25 25 0 0 1 75 49.99999999999999" fill="none" stroke-width="50" stroke="#FF6382"><title>Weak</title></path><text dominant-baseline="central" x="50" y="50" dx="19.151111077974452" dy="16.06969024216348" text-anchor="middle" style="font-size: 5px;">22 %Excellent</text><text dominant-baseline="central" x="50" y="50" dx="-19.15111107797445" dy="16.069690242163485" text-anchor="middle" style="font-size: 5px;">33 %Good</text><text dominant-baseline="central" x="50" y="50" dx="4.341204441673249" dy="-24.620193825305204" text-anchor="middle" style="font-size: 5px;">44 %Weak</text></svg>
This is my Reactjs code:-
const Element = (props) => {
return (
<text
dominant-baseline="central"
x={props.x}
y={props.y}
dx={props.dx}
dy={props.dy}
text-anchor="middle"
style={{ fontSize: "5px" }}
>
{`${Math.round(props.dataEntry.percentage)} %`}
{props.dataEntry.title}
</text>
);
};
This is codesandbox full Reactjs example:-
https://codesandbox.io/s/throbbing-moon-ejs67?file=/src/App.js
How can i line break between the texts (excellent - good ..) and their percentage .
As Danny says - just stick in a tspan. These settings seem to work ok:
const Element = (props) => {
return (
<text
dominant-baseline="central"
x={props.x}
y={props.y}
dx={props.dx}
dy={props.dy}
text-anchor="middle"
style={{ fontSize: "5px" }}
>
{`${Math.round(props.dataEntry.percentage)} %`}
<tspan dx="-12" dy="5">
{props.dataEntry.title}
</tspan>
</text>
);
};

React-Spring — Parallax Issue incorporating a nav and footer due to height constraints

I am using Parallax from react-spring to create a parallax effect. I understand that the can use the height of its parent to set its area. This solution, however, is causing a strange behaviour when scrolling by keeping the and visible on the screen. I have a few questions here:
How can I setup this layout in a way where it will behave normally?
Do I need to place the and inside the ParallaxComp with fixed heights (I am hoping there is a better solution)?
Is there a way to make the assume its height based on the contents inside rather than use the prop factor?
Thank you in advance.
Codesandbox
App.js
import React from "react";
import ParallaxComp from "./ParallaxComp";
import "./styles.css";
export default function App() {
return (
<div className="App">
<nav style={{ height: "5rem", background: "purple", color: "white" }}>
Nav
</nav>
{/* <main style={{ height: "100%" }}> */}
<main style={{ height: "100vh" }}>
<ParallaxComp />
</main>
<footer style={{ height: "5rem", background: "blue", color: "white" }}>
Footer
</footer>
</div>
);
}
ParallaxComp.js
import React from "react";
import { Parallax, ParallaxLayer } from "react-spring/renderprops-addons";
let parallax;
const ParallaxComp = () => {
return (
<Parallax pages={2} scrolling={true} vertical ref={ref => (parallax = ref)}>
<ParallaxLayer
offset={0}
speed={0.1}
style={{
fontSize: "23.47222vw",
textAlign: "right",
textTransform: "uppercase"
}}
>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 948.26 1122.2">
<path
d="M887 0c0 224.45-182.22 406.4-407 406.4S73 224.45 73 0h814z"
fill-rule="evenodd"
clip-rule="evenodd"
fill="#fec70e"
/>
</svg>
</ParallaxLayer>
<ParallaxLayer
offset={0}
speed={-0.4}
style={{
fontSize: "23.47222vw",
textAlign: "right",
textTransform: "uppercase"
}}
>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 948.26 1122.2">
<path
d="M216 105.2c0 59.65-48.35 108-108 108S0 164.84 0 105.2h216z"
fill-rule="evenodd"
clip-rule="evenodd"
fill="#037e36"
/>
</svg>
</ParallaxLayer>
</Parallax>
);
};
export default ParallaxComp;

Firefox does not animate when <g> component attributes change

I'm creating some animated React components in SVG. When I run it in Chrome, the animation works, but when I run it in Firefox, it doesn't.
Here is an example:
const [x, setX] = useState(0)
useEffect(() => {
setTimeout(() => {
setX(100)
}, 3000)
}, [])
return (
<svg width={500} height={300}>
<g transform={`translate(${x}, ${0})`} style={{ transition: "3s all" }}>
<rect width={50} height={50} x={0} y={0} fill={'#f00'} />
</g>
</svg>
)
You can see that it works in Chrome, but not in Firefox: https://codesandbox.io/s/gracious-ives-ykmfp
If I remove the transform in g and change direct in x prop of the rect, that way will work in Firefox, but I don't want to do it that way.
Any help?
The transform attribute is not the same as the transform CSS property, even though it can be confusing (and apparently the two will be merged).
Instead of using the attribute, move the transform to the style property:
const [x, setX] = useState(0);
useEffect(() => {
setTimeout(() => {
setX(100);
}, 3000);
}, []);
return (
<svg width={500} height={300}>
<g style={{ transform: `translate(${x}px, 0px)`, transition: 'all 3s' }}>
<rect width={50} height={50} x={0} y={0} fill={'#f00'} />
</g>
</svg>
);
Demo: https://codesandbox.io/s/nifty-snowflake-664rk
Try to move the transform property to the style. It works for me this way in FF.:
<g style={{transform: `translateX(${x}px)`, transition: "3s all" }}>
<rect width={50} height={50} x={0} y={0} fill={"#f00"} />
</g>
https://codesandbox.io/s/musing-cdn-7eqg0

Resources