Use a single codebase to render svg on Sketch, Web and React Native, but react-primitives
doesn't support svg yet. One suggestion is to use react-primitives-svg
, but there's an issue when trying to render it on the web, as described in airbnb/react-sketchapp#265.
We could directly use the core.web.js
file as below. Also there might be a way to pick up the .web.js
extension just as .android.js
and .ios.js
.
// Svg.js
import { Platform } from "react-primitives";
let SvgLib;
switch (Platform.OS) {
case "sketch":
SvgLib = require("react-primitives-svg/lib/core.sketch");
break;
case "web":
SvgLib = require("react-primitives-svg/lib/core.web");
break;
default: // React Native should be able to pick up `core.ios.js` or `core.android.js` according to the platform
SvgLib = require("react-primitives-svg");
}
export const { Svg, Path } = SvgLib;
// App.js
import { Svg, Path } from './Svg';
...
const App = () => (
<View>
<Svg viewBox="0 0 24 24" style={{ fill: 'blue'}}>
<Path d='M23.44 4.83c-.8.37-1.5.38-2.22.02.93-.56.98-.96 1.32-2.02-.88.52-1.86.9-2.9 1.1-.82-.88-2-1.43-3.3-1.43-2.5 0-4.55 2.04-4.55 4.54 0 .36.03.7.1 1.04-3.77-.2-7.12-2-9.36-4.75-.4.67-.6 1.45-.6 2.3 0 1.56.8 2.95 2 3.77-.74-.03-1.44-.23-2.05-.57v.06c0 2.2 1.56 4.03 3.64 4.44-.67.2-1.37.2-2.06.08.58 1.8 2.26 3.12 4.25 3.16C5.78 18.1 3.37 18.74 1 18.46c2 1.3 4.4 2.04 6.97 2.04 8.35 0 12.92-6.92 12.92-12.93 0-.2 0-.4-.02-.6.9-.63 1.96-1.22 2.56-2.14z' />
</Svg>
</View?
);
export default App;
const buttonColors = {
pink: {
background: '#fff',
border: '#D82662',
text: '#D82662'
},
pinkFill: {
background: '#D82662',
border: '#D82662',
text: '#fff'
},
noFill: {
background: '#fff',
border: '#fff',
text: '#D82662'
},
grey: {
background: '#fff',
border: '#D5D5D5',
text: '#707070'
}
};
const getBackgroundColor = color => buttonColors[color].background;
const getBorderColor = color => buttonColors[color].border;
const getTextColor = color => buttonColors[color].text;
const ButtonContainer = styled.View`
border: 1px solid ${props => getBorderColor(props.color)};
border-radius: 5px;
background: ${props => getBackgroundColor(props.color)};
padding: 12px 20px;
margin: 0px 0px 10px;
flex: 1;
flex-basis: 100%;
`;
const ButtonText = styled.Text`
color: red;
color: ${props => getTextColor(props.color)};
font-family: 'OpenSans-Bold';
font-size: 16px;
line-height: 22px;
text-align: center;
width: 160px;
`;
export default class Button extends Component {
render() {
return (
<ButtonContainer>
<ButtonText>
{this.props.children}
</ButtonText>
</ButtonContainer>
);
}
}
Starting from the error message:
TypeError: undefined is not an object (evaluating 'buttonColors[color].background`)
This means, at some point in the code, the value of buttonColors[color]
is undefined
, but we are trying to use it as an object -- we are trying to get its background
property with .background
.
Searching in the code, it's this line:
const getBackgroundColor = color => buttonColors[color].background;
This is an arrow function named getBackgroundColor
. Who calls it?
Keep searching... This is the only place where the method is called:
const ButtonContainer = styled.View`
...
background: ${props => getBackgroundColor(props.color)};
...
`;
Here, props.color
is passed into getBackgroundColor
and used as the color
in buttonColors[color].background
.
What's its value? Let's find out!
We'll use console.log
to print out the value of props.color
and see if we could find any clue.
const ButtonContainer = styled.View`
...
background: ${props => {
console.log('=========> props.color=', props.color);
return getBackgroundColor(props.color)};
}
...
`;
If you run it, you'll see this in the console output (see here if you are using React Sketch.app)
=========> props.color=undefined
Alright, so basically we pass an undefined
into getBackgroundColor
. What is the value of buttonColors[undefined]
? It's undefined
as well, right?
But wait a second, why is props.color
undefined
? The question is, what is this props
? It's the props we give to the ButtonContainer
component, right?
However, look at how we use the ButtonContainer
component:
<ButtonContainer>
<ButtonText>
{this.props.children}
</ButtonText>
</ButtonContainer>
What are the props of ButtonContainer
? Nothing! There are no props whatsoever. There is no doubt that props.color
is undefined
.
I'll leave it to you. There will be another similar error in this code as well, fix it in the same way.
- Don't panic
- Read the error message carefully and try to make sense of it
- Follow the code execution backwards, search in the code
console.log
You legend! I finally got it working thats to your code.
It renders to Web and Sketch, just not Native yet.
I think the issue was over dependencies and possible version conflicts. This setup seemed to work:
"chroma-js": "^1.2.2", "nwb": "^0.15.6", "react": "^16.2.0", "react-dom": "^16.2.0", "react-native": "^0.53.2", "react-native-svg": "^6.2.1", "react-primitives": "^0.5.0", "react-primitives-svg": "0.0.3", "react-sketchapp": "^1.0.0", "react-test-renderer": "^16.2.0", "styled-components": "^3.1.6", "webpack": "^3.11.0"
But I don't know anything about
nwb
and can't see whychroma-js
was needed.The errors below may have also been related to me editing the package.json file directly.