-
Notifications
You must be signed in to change notification settings - Fork 4.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
React Native - SVG icons for Inserter #9294
Conversation
…ading, more and paragraph blocks
…idth do not have to be indicated explicitely
There are some linting issues which prevents this PR from being merged. You can see them on Travis: https://travis-ci.org/WordPress/gutenberg/jobs/419924102
|
@mtias @jasmussen - out of curiosity, how are those new SVG icons generated? I'm asking because we need to take into account the needs of React Native environment moving forward where we will have to use imported primitive components which allow to branch code between web and mobile. |
{ props.children } | ||
</Svg> | ||
); | ||
} else { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Svg implementation handles viewBox
out of the box:
https://github.com/react-native-community/react-native-svg/blob/master/elements/Svg.js#L35
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's right viewBox
is handled, but the component will fail to render if height
and width
are not set - what this (most probably hack-ish) piece of code does is fabricate the height and width out of the information passed in viewBox
which seemed to exist in all cases for all blocks in code (I relied on that to process unless width
and height
are explicitely set through props). For this I separated this specific change in commit c75a0db wdyt?
Svg, | ||
} from 'react-native-svg'; | ||
|
||
export const Path = PATH; | ||
export const G = GROUP; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You don't need to alias those components, you can do the following instead:
import {
G,
Path,
Svg
} from 'react-native-svg';
export {
G,
Path,
};
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
addressed in bf65beb
// take viewport system to match the viewBox definition | ||
// i.e. viewBox="0 0 24 24" | ||
let viewBoxCoords = props.viewBox.split(' '); | ||
return ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think @SergioEstevao had an issue with one of the passed props. I was wondering if usin omit from 'lodash' would work here:
export const SVG = ( props ) => {
return <Svg { ...omit( props, [ 'className' ] } />;
};
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That was the problem, RN complained about className being set. if omit takes it away it could work :).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is going to be a recurring issue, it would be nice to find a way to skip those className
properties or convert them to style
. Ideally, it would work out of the box.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tested it a bit and it seems to be working 👍
addressed in 6d5b37d
@@ -8,6 +8,7 @@ import { createBlock } from '@wordpress/blocks'; | |||
* Internal dependencies | |||
*/ | |||
import edit from './edit'; | |||
import { Path, SVG } from '@wordpress/components'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It should be put under WordPress dependencies
section. See related coding guidelines: https://github.com/WordPress/gutenberg/blob/master/docs/reference/coding-guidelines.md#imports.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! addressed in ed725d6
@@ -20,7 +20,8 @@ import { RichText } from '@wordpress/editor'; | |||
* Internal dependencies | |||
*/ | |||
import edit from './edit'; | |||
|
|||
import { Path, SVG } from '@wordpress/components'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The same thing with WordPress dependencies
section.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
addressed in ed725d6
@@ -14,6 +14,7 @@ import { createBlock } from '@wordpress/blocks'; | |||
* Internal dependencies | |||
*/ | |||
import edit from './edit'; | |||
import { Path, G, SVG } from '@wordpress/components'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The same thing with WordPress dependencies
section :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same as above
@@ -25,6 +25,7 @@ import { | |||
* Internal dependencies | |||
*/ | |||
import edit from './edit'; | |||
import { Path, SVG } from '@wordpress/components'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The same thing with WordPress dependencies
section 😅
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
:) same as above, addressed in ed725d6
That's the thing. We can't know. Because plugins add these, so they could be using horribly mangled SVGs. As is also discussed in #9269 (comment), this also has accessibility implications. Do we have any way to build a tool to parse the SVG source files and serve a sanitized version on the fly? |
I wouldn't worry about it too much. We didn't even start discussing what needs to happen to enable plugins on mobile. I can imagine this is going to be opt-in because you will have to operate on a much more constrained environment. You won't be able to use DOM element as they are. SVG is just and example.
I don't think there is one, however it isn't that complex. In the majority of cases, the only thing you need to change is to capitalize tag name. SVG is the only exception because it needs to follow our coding guidelines. Please also note that you can't fully copy |
…own to Svg component
- Fix an issue where eventCount was not correctly propogated to AztecText resulting in a re-rendering of the component from scratch
export const SVG = ( props ) => { | ||
// for some reason if a `className` prop is passed it gets converted to `style` here. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The reason the className
gets transformed into style
is because on the RN side, the babel-plugin-react-native-classname-to-style
is active. That was part of the work done in order to support SCSS on the RN app. See this PR.
What exactly is the problem when style
appears? Is the Svg
component not using it or does it choke on it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
citing the comment: Given it carries a string (as it was originally className) but an object is expected for "style"
... it chokes :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also thanks for pointing that out (about the PR where this change is implemented). We discussed that elsewhere and forgot to add this here. It might be good to change the comment to add this information in particular, adjusting the "for some reason..." part.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comment modified in 5227859
// We're using the react-native-classname-to-style plugin, so when a `className` prop is passed it gets converted to `style` here. | ||
// Given it carries a string (as it was originally className) but an object is expected for `style`, | ||
// we need to check whether `style` exists and is a string, and strip in that case. | ||
const safeProps = ( typeof props.style === 'string' || props.style instanceof String ) ? { ...omit( props, [ 'style', 'className' ] ) } : { ...omit( props, [ 'className' ] ) }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Feels super weird to have to manually strip the style definition so, if you don't mind @mzorz , let's dig a little deeper in this one.
We already had a chat over Slack with what probably needs to be done here (properly load the styles for RN) so, let's wait a bit to finish that effort, is that OK?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As discussed with @hypest , made the style
convert from string to object properly (if it applies) in 2d47451 and b678c6d.
To test, I added the following:
.dashicons-editor-bold {
transform: rotate(20deg);
}
to packages/components/src/dashicon/style.scss
and the styles get passed to the svg component, this is how the bold icon gets rendered:
See the B icon slightly leaning to the right? 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Out of curiosity, why does it happen that style becomes a string?
On the web you have to pass an object as style, I think this is also the case in React Native. So this is very surprising. I would love to understand why this is something we need to handle in the first place.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As far as I understand, className
is not supported in React Native, so we need to define that as a prop on each object we'd want to use that in.
Because of this and being that className
is being used in different places in Gutenberg, we're using a Babel plugin that transforms className
to style
in RN so to make it transparent to Gutenberg code.
AFAIU the plugin just keeps the passed object as it was without making any other conversion, so if the original object was a string, it will be a string after going through it as well.
So knowing this, it looks like the problem arises then because Dashicon gutenberg/packages/components/src/dashicon/index.js
declares className={ iconClass }
where iconClass
is a string, a defined here: https://github.com/WordPress/gutenberg/blob/master/packages/components/src/dashicon/index.js#L899
While className
can be a string (as it originally is in Dashicon code), style
should be an object instead, but we're not transforming it (just keeping the same type).
Does that make sense? Should we do something differently? cc @hypest as well to see if there's something else to add / do differently in this regard.
…ing on svgnative implementation
This needs to be synced with the web implementation. We discussed it a few times with @jasmussen and there is no clear way to move forward. It would be great if we could figure out a solution where we would be able to use SVG as is generated and convert it to React element on the fly, for web it would be possible with this Babel plugin: |
@gziolo I wonder, can we perhaps abstract away the value of the |
I'm curious, what's the reasoning behind inlining SVGs? Could we keep them as a file and use |
It's more or less the same, not going into detail, it would work on a higher level as you described. |
In the rendered code, we need the SVGs to be inline so we can colorize them using |
One of the challenges we are also facing (see #9565) is that we need a few attributes added to the SVG, which we can't assume are always there. |
I'm playing with an alternative approach in #9685. The idea is as follows:
|
From #9685 (comment):
@mzorz , let's try updating from |
Yes, let's try to use primitives I exposed in #9685 while I experiment with adding support for HTML tags. I didn't make it work so far and the more I think about it, the more it seems like having abstraction layer is a more elegant solution. In particular, it might be more reliable when using with all 3rd party libraries which use React directly. I think this is the biggest challenge to ensure that |
Just finished updating this branch to |
…act Native compatibility
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM! Feel free to merge as soon as Travis gives the green light too!
Description
This PR adds mobile SVG compatibility in React Native for SVG icons of already ported blocks:
How has this been tested?
Using this PR in the Gutenberg mobile repo
Screenshots
Types of changes
This PR
<g>
tag in the for ofG
as needed by our wrapper libraryicon:
prop declaration for the aforementioned blocks to use the wrapper<SVG
tag as follows:What was til now declared as:
is now declared as:
Checklist: