Current State
We are implementing edit function separately for each block to work on the mobile editor. We are not reusing any of the css web has, we have separate x.native.scss files for almost all the blocks that we developed.
Here's a very simple PR that shows how a new block is added on mobile editor. Please also follow the link to the gutenberg side PR in the description to be able to see all changes.
What we are trying to change
We need to find a way to make the following possible as much as possible: "implement the block once, run on both mobile & web". There are different ways to approach this problem and we tried out some of them in the past, those solutions are also OK but we didn't try to see our limits about how much code reuse we can do on lower level. Here are some cross platform blocks we already have: separator, quote. Every sub component these blocks have are implemented for both mobile and web so we can just use those components to construct these blocks with a single file. This is a good approach but at the same time requires us to implement mobile versions of every component separately. So it can be called as a high level approach. We want to see what can be possible on the lower level, like how to translate a simple div to a View transparently and how to translate the css to mobile style objects transparently? Or another approach could be, abstracting out web elements so that we can use a very straight forward replacement method to change them with their x-platform equivalents. So basically we want to see our limitations about how much of the already written web code/css we can make it work on mobile side by doing some architectural solutions.
Expected outcome from this PoC
Although we chose Gallery block for this PoC we expect that the outcome won't be just delivering the Gallery block in an x-platform form but also developing a method that can be applied to other blocks.
How can we break this down into smaller tasks
At this step we don't need to focus on MediaUpload, InspectorControls, MediaPlaceholder etc. We are only focusing on what we see between <ul> tags here and trying to make that part of the code work on both mobile and web.
In order to be able to test this, your post should already have a gallery added into it. You can either add such a post via the web editor or you can try putting this piece of html by switching to the html mode which can be reached via the right ... button on navigation bar. Or for the example app you can just put this sample piece of code into src/initial-html.js.
<!-- wp:gallery {"ids":["31","33","36","8"]} -->
<ul class="wp-block-gallery columns-3 is-cropped"><li class="blocks-gallery-item"><figure><img src="https://images.pexels.com/photos/373893/pexels-photo-373893.jpeg" alt="" data-id="31" class="wp-image-31"/></figure></li><li class="blocks-gallery-item"><figure><img src="https://images.pexels.com/photos/1034662/pexels-photo-1034662.jpeg" alt="" data-id="33" class="wp-image-33"/></figure></li><li class="blocks-gallery-item"><figure><img src="https://images.pexels.com/photos/830891/pexels-photo-830891.jpeg" alt="" data-id="36" class="wp-image-36"/></figure></li><li class="blocks-gallery-item"><figure><img src="https://images.pexels.com/photos/290595/pexels-photo-290595.jpeg" alt="" data-id="8" class="wp-image-8"/></figure></li></ul>
<!-- /wp:gallery -->
How to register Gallery block on Mobile
Currently Gallery block is not present on the mobile app, it needs to be registered in packages/block-library/src/index.native.js for that. You can refer to this PR to see how that file is edited to register a new block.
Experimental branches
I'll share some experimenting branches to give an idea about what we have tried so far but keep in mind that these are in a very very raw state and there are lots of unnecessary code in them just added for debugging purposes. I am just sharing these to help with the onboarding and to help you get familiar with the topic.
One of them is this branch you can see a small attempt about how to transparently render mobile components under the hood even if web elements are used. We have also a separate experiment here (gb-mobile branch, gutenberg branch) which brings a more manual approach on replacing web elements. Both branches are missing a proper css solution and we are currently working on that.
Please do not limit yourselves with these approaches, we'd appreciate different point of views. Feel free to create new branches for trying out other ideas.
As you know that not all of code can be shared between web and mobile. Ideal candidate to share is logic, but if we want to share UI components as well, the best way is to create additional layer which translates from mobile to web or from web to mobile.
In this case it's from web to mobile because web is already implemented.
Ideal solution in my mind is to use styled-components, but I understand that it would be hard (impossible) to migrate and require from "plugins developers" to do the same.
There is a really small, simple and old project that i did with this stack https://github.com/callstack/universal-react-app
However i see few issues that could be hard to solve or code that can not be shared and i know there is probably more of them:
react-native-sass-transformerwindow.onresize, window.onunload etcI checked your approach of code sharing and there are my thoughts :)
createElement approach
"primitives" approach
I think that in both cases there will be also an issue with lists. FlatList is more performant than View nested in View, but FlatList needs to use renderProp instead of map of components like <ul><li> as a children prop.
I would suggest the approach with primitives because i feel it more readable, flexible and maintainable.
Thanks for the insights @dratwas. I think universal-react-app demonstrates a similar solution to the one I referred as 'high level approach' which we already used on the separator, quote blocks. It is actually the solution we are planning to fallback to if things don't go well during our experiments about css.
We are actually not trying to support everything about css, it'd be impossible to do such a thing inside the context of our project, but we are just searching for ways to expand our current support on scss files. For example this package demonstrates a similar attempt to what we are trying to achieve. They chose some mostly used css selectors and developed a way to support those on mobile. So we are exploring these kind of solutions to get some inspiration from and combine them with our own insights to create the solution best fitting to our needs. Which is reusing the already present code as much as possible with some architectural workarounds. With this said, we aren't planning to dedicate too much time on this experimental phase unless we see some promising results in the following days. So If you have some ideas that can help on this architectural tweaks we'd be very interested in hearing them firstly, otherwise you can also try out your current proposal in a separate branch and we can also discuss on that. If you need any kind of questions/support about anything don't hesitate to give a ping.
@pinarol, I would like to collect all the approaches which have been checked so far.
In the case of cross-platform components, you were experimenting with:
primitives - a correct approach (components with partially unified API are created in one place and then are consumed by other components) which creates an additional layer without any impact on performance.
createElement - solution used in a fundamentals components in react-native-web. Similarly to your PoC there is a custom method called createElement and then used e.g. in PickerItem or Image:
createElement('img', {
alt: accessibilityLabel || '',
classList: [classes.accessibilityImage],
draggable: draggable || false,
ref: this._setImageRef,
src: displayImageUri
})
@lukewalczak Did you have a chance to investigate an approach that can help with reusing the existing css to some extend?
I think this PoC is definitely worth going on but if there are other opinions you might have for the increasing the css support on mobile components we'd love to hear those too(Or any opinions for not pursing that way).
And about the PoC I have some small comments:
https://github.com/WordPress/gutenberg/compare/master...lukewalczak:try/rn-primitives#diff-753b1add48ade5f30fe91e105cff6457R10
This is prolly still work in progress but as far as I see the Text import here only supported for mobile.
import { Component, Text, List } from '@wordpress/element';
I'd not expect having 2 different set of components that are exported from typography/index.js and typography/index.native.js becase this way we can't have a single component that uses them for mobile and web.
Also I think this classname won't be rendered for web.
<List
classname={ [ styles[ 'wp-block-gallery' ] ] }
We are aiming for a single gallery/edit.js at the end of this work without needing to have a gallery/edit.native.js What I can suggest for now is making sure things are rendered on web as well.
Thanks for all the effort!
cc @koke @mkevins
Did you have a chance to investigate an approach that can help with reusing the existing css to some extend?
Unfortunately, not yet. We'll see what can we achieve with that next week.
This is prolly still work in progress
Yes, this was a quick draft where I wanted mainly to present how to handle <ul> in my opinion.
What I can suggest for now is making sure things are rendered on web as well.
Can you please tell us / point us to doc how to do this properly?
Can you please tell us / point us to doc how to do this properly?
Sure thing!
This page has necessary steps about how to get up the gutenberg web. If you have trouble at this step please give a ping to our channel on slack.
After getting it up go to http://localhost:8888/wp-admin/
navigate to Posts > Add new
You can use (+) button to see the block picker and search for gallery block there
Or you can switch to Code Editor mode from the vertical 3dots on the right top and paste the gallery html there directly and switch back to Visual editor.
One thing I can remind, in the past we saw that sometimes doing this under gutenberg-mobile/gutenberg could produce some problems, so if things start to seem crazy on mobile you can remove everything under gutenberg-mobile/gutenberg/node_modules, checkout gutenberg on a separate folder and get it up from there.
Let me know if you come across with any problems @lukewalczak
I am going to close this issue as we shared different approaches in the p2.
Most helpful comment
As you know that not all of code can be shared between web and mobile. Ideal candidate to share is logic, but if we want to share UI components as well, the best way is to create additional layer which translates from mobile to web or from web to mobile.
In this case it's from web to mobile because web is already implemented.
Ideal solution in my mind is to use styled-components, but I understand that it would be hard (impossible) to migrate and require from "plugins developers" to do the same.
There is a really small, simple and old project that i did with this stack https://github.com/callstack/universal-react-app
However i see few issues that could be hard to solve or code that can not be shared and i know there is probably more of them:
react-native-sass-transformerwindow.onresize,window.onunloadetcI checked your approach of code sharing and there are my thoughts :)
createElement approach
"primitives" approach
I think that in both cases there will be also an issue with lists. FlatList is more performant than View nested in View, but FlatList needs to use renderProp instead of map of components like
<ul><li>as a children prop.I would suggest the approach with primitives because i feel it more readable, flexible and maintainable.