Git Product home page Git Product logo

react-primitives's Introduction

react-primitives

Primitive React Interfaces Across Targets

npm

Installation

npm install --save react-primitives

You will also need to install the targets you want to support:

  • web:
    npm install --save react-dom react-native-web react-art
  • native iOS and Android:
    npm install --save react-native
  • sketch:
    npm install --save react-sketchapp react-test-renderer
  • figma:
    npm install --save react-figma
  • vr:
    npm install --save react-360
  • Windows:
    npm install --save react-native-windows

Usage

import React from "react";
import { View, Text, Image, StyleSheet } from "react-primitives";

class Foo extends React.Component {
  render() {
    return <View style={styles.foo}>{this.props.children}</View>;
  }
}

const styles = StyleSheet.create({
  foo: {
    width: 100,
    height: 100,
    backgroundColor: "#ff00ff"
  }
});

What is this?

This library attempts to propose an ideal set of primitives around building React applications, regardless of Platform. In the future, this could be used as a shared interface among React and React Native components that don't use platform-specific APIs.

Importantly, this includes StyleSheet for declaring styles, as well as Animated for doing declarative Animations.

The exported APIs thus far are:

  1. Animated: Pulled from the animated project.
  2. StyleSheet: Follows React Native's StyleSheet API.
  3. View: A base component for Layout.
  4. Text: A base component for Text rendering.
  5. Image: A base component for Image rendering.
  6. Touchable: A base component for interaction.
  7. Easing: A base set of easing functions.
  8. Dimensions: Get the devices dimensions.
  9. PixelRatio: Get the devices pixel density.
  10. Platform: Get information about the platform. (iOS, Android, Web, Sketch, VR,...)

In the future, a TextInput component may also be added.

Props where props are due

This library was largely inspired from the work done by Nicolas Gallager and his great work on the react-native-web library. A few of the files in this repo are even copied directly from his project.

react-primitives's People

Contributors

anthonykrivonos avatar brodybits avatar davidpett avatar hermanya avatar ilyalesik avatar jevakallio avatar kkemple avatar lelandrichardson avatar lencioni avatar likethemammal avatar macintoshhelper avatar mathieudutour avatar metakermit avatar msand avatar mxstbr avatar sawa-zen avatar thetechie avatar tkow avatar wyattdanger avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

react-primitives's Issues

Use react-native-web

This package largely copy-pastes or reimplements react-native-web for the web implementation. You could simply depend on react-native-web and contribute any adjustments required. That project also has better test coverage and more correct implementations. Let me know if you'd like to discuss further

Future of primitives?

I've been using this project for a while and I think that the idea is great!

Recently I started thinking, which way is to project heading to?

You have said that you aren't sure yet, which components are the right primitives.
Many people have proposed the idea of adding TextInput as a primitive since it's desperatly needed for many apps.
First I thought that TextInput should be added as a primitive since you can't even make a simple (login) form without it.
I think that it's needed in all the targets mentioned in this projects issues (web, mobile, vr, sketchapp, console), but after a while I've also have come to the same conclusion that it shouldn't be added.

The reason is that TextInput has platform specific logic and some targets can't even implement it.

Even when the basic idea for TextInput is the same across most of the targets, the platform specific nuances make it a different kind of a component on each target. I think that the same issues arise with Touchable.

What if we remove all those problematic components/apis?

Then we face an issue where no developer would choose to use react-primitives in their library since it lacks most of the required components for their needs. The developer would have to use platform extensions for a lot of stuff if they decided to use react-primitives.

This becomes an issue because now let's say we have some cool library for mobile and the developer used react-primitives, but the library uses TextInput from react-native.
Now a new developer wants to use this for some other target (that can implement TextInput somehow).
The new developer can't use it unless the libs developer refactors that TextInput usage in a separate file and uses platform extensions to support that new target.

This adds lots of frustration for developers and libraries will most likely just keep supporting that one target.

One possible solution:
Split primitives into multiple smaller projects (lerna monorepo?)
Keep primitives base very small. Example just View, Text, Image, StyleSheet.
Now we can have the more problematic components/apis in separate projects.
Then we don't have to bloat base with ”must have components” and introducing new targets isn't so exhausting.

The maintainer(s) of the new target could make PRs for each react-primitives-X project that they see fit.

This doesn't necessarily solve any problems, but could make primitives more usable across all targets.

Now in that mobile lib example the new developer could just ask react-primitives-input library developer to support the new target instead of asking dozens of some other library developers to support his/her target.

Any thoughts on this @lelandrichardson ?

Error touchableGetInitialState is not a function

Love this package, unfortunately it just broke.

I got the this.touchableGetInitialState is not a function error on this config

{
"react": "16.0.0-alpha.12",
"expo": "^18.0.3",
"react-native": "^0.45.1",
"react-primitives": "^0.4.3",
}

exact error message

Possible Unhandled Promise Rejection (id: 0): TypeError: this.touchableGetInitialState is not a function. (In 'this.touchableGetInitialState()', 'this.touchableGetInitialState' is undefined)

<Image> doesn't work with data URIs

It seems like the background image isn't getting set for some reason

const uri = `data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 841.9 595.3"><g fill="#61DAFB"><path d="M666.3 296.5c0-32.5-40.7-63.3-103.1-82.4 14.4-63.6 8-114.2-20.2-130.4-6.5-3.8-14.1-5.6-22.4-5.6v22.3c4.6 0 8.3.9 11.4 2.6 13.6 7.8 19.5 37.5 14.9 75.7-1.1 9.4-2.9 19.3-5.1 29.4-19.6-4.8-41-8.5-63.5-10.9-13.5-18.5-27.5-35.3-41.6-50 32.6-30.3 63.2-46.9 84-46.9V78c-27.5 0-63.5 19.6-99.9 53.6-36.4-33.8-72.4-53.2-99.9-53.2v22.3c20.7 0 51.4 16.5 84 46.6-14 14.7-28 31.4-41.3 49.9-22.6 2.4-44 6.1-63.6 11-2.3-10-4-19.7-5.2-29-4.7-38.2 1.1-67.9 14.6-75.8 3-1.8 6.9-2.6 11.5-2.6V78.5c-8.4 0-16 1.8-22.6 5.6-28.1 16.2-34.4 66.7-19.9 130.1-62.2 19.2-102.7 49.9-102.7 82.3 0 32.5 40.7 63.3 103.1 82.4-14.4 63.6-8 114.2 20.2 130.4 6.5 3.8 14.1 5.6 22.5 5.6 27.5 0 63.5-19.6 99.9-53.6 36.4 33.8 72.4 53.2 99.9 53.2 8.4 0 16-1.8 22.6-5.6 28.1-16.2 34.4-66.7 19.9-130.1 62-19.1 102.5-49.9 102.5-82.3zm-130.2-66.7c-3.7 12.9-8.3 26.2-13.5 39.5-4.1-8-8.4-16-13.1-24-4.6-8-9.5-15.8-14.4-23.4 14.2 2.1 27.9 4.7 41 7.9zm-45.8 106.5c-7.8 13.5-15.8 26.3-24.1 38.2-14.9 1.3-30 2-45.2 2-15.1 0-30.2-.7-45-1.9-8.3-11.9-16.4-24.6-24.2-38-7.6-13.1-14.5-26.4-20.8-39.8 6.2-13.4 13.2-26.8 20.7-39.9 7.8-13.5 15.8-26.3 24.1-38.2 14.9-1.3 30-2 45.2-2 15.1 0 30.2.7 45 1.9 8.3 11.9 16.4 24.6 24.2 38 7.6 13.1 14.5 26.4 20.8 39.8-6.3 13.4-13.2 26.8-20.7 39.9zm32.3-13c5.4 13.4 10 26.8 13.8 39.8-13.1 3.2-26.9 5.9-41.2 8 4.9-7.7 9.8-15.6 14.4-23.7 4.6-8 8.9-16.1 13-24.1zM421.2 430c-9.3-9.6-18.6-20.3-27.8-32 9 .4 18.2.7 27.5.7 9.4 0 18.7-.2 27.8-.7-9 11.7-18.3 22.4-27.5 32zm-74.4-58.9c-14.2-2.1-27.9-4.7-41-7.9 3.7-12.9 8.3-26.2 13.5-39.5 4.1 8 8.4 16 13.1 24 4.7 8 9.5 15.8 14.4 23.4zM420.7 163c9.3 9.6 18.6 20.3 27.8 32-9-.4-18.2-.7-27.5-.7-9.4 0-18.7.2-27.8.7 9-11.7 18.3-22.4 27.5-32zm-74 58.9c-4.9 7.7-9.8 15.6-14.4 23.7-4.6 8-8.9 16-13 24-5.4-13.4-10-26.8-13.8-39.8 13.1-3.1 26.9-5.8 41.2-7.9zm-90.5 125.2c-35.4-15.1-58.3-34.9-58.3-50.6 0-15.7 22.9-35.6 58.3-50.6 8.6-3.7 18-7 27.7-10.1 5.7 19.6 13.2 40 22.5 60.9-9.2 20.8-16.6 41.1-22.2 60.6-9.9-3.1-19.3-6.5-28-10.2zM310 490c-13.6-7.8-19.5-37.5-14.9-75.7 1.1-9.4 2.9-19.3 5.1-29.4 19.6 4.8 41 8.5 63.5 10.9 13.5 18.5 27.5 35.3 41.6 50-32.6 30.3-63.2 46.9-84 46.9-4.5-.1-8.3-1-11.3-2.7zm237.2-76.2c4.7 38.2-1.1 67.9-14.6 75.8-3 1.8-6.9 2.6-11.5 2.6-20.7 0-51.4-16.5-84-46.6 14-14.7 28-31.4 41.3-49.9 22.6-2.4 44-6.1 63.6-11 2.3 10.1 4.1 19.8 5.2 29.1zm38.5-66.7c-8.6 3.7-18 7-27.7 10.1-5.7-19.6-13.2-40-22.5-60.9 9.2-20.8 16.6-41.1 22.2-60.6 9.9 3.1 19.3 6.5 28.1 10.2 35.4 15.1 58.3 34.9 58.3 50.6-.1 15.7-23 35.6-58.4 50.6zM320.8 78.4z"/><circle cx="420.9" cy="296.5" r="45.7"/><path d="M520.5 78.1z"/></g></svg>`

// doesn't work:
const ReactLogo = () => <Image source={{ uri }} />

// works:
const ReactLogo = () => <img src={ uri } />

Warning: ReactClass: You're attempting to include a mixin that is either null or not an object.

I am using react-primitives with the latest version of create-react-native-app and am getting this warning. Seems to be a common problem with other packages as well. Or am I doing something wrong?

Warning: ReactClass: You're attempting to include a mixin that is either null or not an object. Check the mixins included by the component, as well as any mixins they include themselves. Expected object but got undefined.

The best way to handle font-face

I'm writing a styled open-sourcable react component. I'd like to use react-primitives to layout and style the whole thing, and there arent many issues I can think of when it comes to using StyleSheet for everything over relying on css, but one comes to mind for this project.

The component will need a custom font as part of it's styling. I know the web and react native each have their own ways of importing custom fonts and setting what fontFamilys are available. But this is such a lightweight component, and it really isnt dependent on react native. I'm basically trying to come up with a way to base64 include the font and set font-face for all platforms.

Is this something that would fall under the .[platform].js pattern, where the .web.js file would be an injectable font-face stylesheet, and the react native file would have it's equivalent? Or is this something StyleSheet could handle? Or is this a situation where I'd just have to instruct in my documentation to include a font-face stylesheet when using the component for web, and follow the traditional react-native custom font importing instructions for the native platforms?

I'm trying to avoid that moment of

"Hey, thanks for installing this package. Now figure out how to include this font to make it look right"

react-primitives is not transpiling when bundling for react-native production

In my react-native project

node ./node_modules/react-native/local-cli/cli.js bundle --entry-file index.ios.js --platform ios --dev false --reset-cache --bundle-output /tmp/main.jsbundle --assets-dest /tmp/
**TypeError: /Users/peterp/Personal/xxx/node_modules/react-primitives/lib/modules/Platform.js: Property left of AssignmentExpression expected node to be of a type ["LVal"] but instead got "StringLiteral"**
transform[stderr]:     at Object.validate (/Users/peterp/Personal/xxx/node_modules/babel-types/lib/definitions/index.js:109:13)
transform[stderr]:     at Object.validate (/Users/peterp/Personal/xxx/node_modules/babel-types/lib/index.js:505:9)
transform[stderr]:     at NodePath._replaceWith (/Users/peterp/Personal/xxx/node_modules/babel-traverse/lib/path/replacement.js:176:7)
transform[stderr]:     at NodePath.replaceWith (/Users/peterp/Personal/xxx/node_modules/babel-traverse/lib/path/replacement.js:160:8)
transform[stderr]:     at PluginPass.MemberExpression (/Users/peterp/Personal/xxx/node_modules/metro-bundler/build/JSTransformer/worker/inline.js:126:14)

I've narrowed it down the assignment here: https://github.com/lelandrichardson/react-primitives/blob/master/src/modules/Platform.js#L13

Number of classes generated

This is more of a question, and request for information, rather than a specific issue - however in terms of development maintenance and code readability you could class it as an issue.

I have created a component using react-primitives, comprising some common elements.

<Touchable onPress={() => console.log("Button Press")}> <View style={styles.button}> <View style={styles.icon}></View> <Text style={styles.label}>{label}</Text> </View> </Touchable>

All works great, react-primitives library is great.

My question/query is - what is the need for so many generated classes?

For example, in development workflow the classes great in number:
react-primitives-component-classes-development

Even in a production build, the number of classes is great:
react-primitives-component-classes-production

As I said, it's not necessarily a bug, it could be considered an issue in terms of development maintenance and code readability. I'm more asking for opinions and advice (if there is a way to optimise further).

Thanks in advance.

this.touchableGetInitialState is not a function

I've been trying to get react-primitives and styled components going on a project so have been doing some research this week without luck on running it on Native. I've decided to import it from a fresh basic react-native initialized project and am getting this error on Touchable.

All I've done from the basic init is add <Touchable><Text>This is inside a touchable</Text><Touchable> to the App.js file.

Upon inspection of the lib directory, it looks like the issue might be related to the React.createClass function not bringing in the mixins properly. The function itself is in the TouchableMixin file and looks to be properly added to the createClass function. I wonder if the newer React 16 requirements have caused this.

I'd be happy to help refactor these classes up to React 16 if we can prove this is the issue.

Thanks for the insight.

react-native-web vs react-web

I noticed pseudo-selectors and media-queries are implemented in the StyleSheet defined in src/web/, however trying to use a pseudo-selector the same way they're used in tests leads to the following error:

Warning: ":hover" is not a valid style property.
StyleSheet body: {
  "width": 30,
  ":hover": {
    "width": 20
  }
}

This is because the StyleSheet object being imported on web is the one from react-native-web, which does not implement pseudo-selectors. So that leads me to my question: what's the the story behind react-web and what are your plans for it?

This is a sweet project and it was awesome meeting you at Chain React!

Support for ul, buttons, icons?

I'm new to this library, but would like to explore it alongside React Sketchapp for my designs & React web applications.

After playing w/ the examples in Sketch App, it looks like we have support for the following via primitives:

View -> renders div
Image -> renders img
Text -> renders span

Is there a suggested practice for rendering other web element types? I guess a few that come to mind immediately are some already mentioned I believe...

ul for lists
button for buttons
i for icons
input for inputs

It would be nice to have a doc detailing what the recommended primitives are for each element type...

Thanks so much for all your hard work on this. This is amazing!!!

StyleSheet and non-primitive DOM elements

What is the best way to use StyleSheet to style non-primitive web DOM elements?

From what I've gathered, react-primitives is using StyleSheet from react-native-web. It's possible to implement most things out of the basic react-primitives (View, Image, Text, Touchable) + accessibilityRole, but sometimes you still need to use the DOM elements like input or textarea.

React DOM doesn't accept StyleSheet objects. It does seem like it's possible to do this:

<input type="text" style={StyleSheet.flatten(styles.input)} />

But you miss out on the css optimization of the generated classes and there are some inconsistencies between react style and react-native style (line-height as a multiplier vs pixel value).

It looks like the react-primitives have their styles processed as part of applyPrimitiveMethods, but I haven't figured out how to use that in my own components. react-native-web has a createDOMElement function, but I don't think that's included in react-primitives.

Any ideas or guidance would be much appreciated! :)

What about scrollview?

I feel like ScrollView is an essential part of these primitives, I can't remember any app that I built without it.

React 16 Support

Currently this is blocked on an upstream dependency, react-native-web - they're tracking this at necolas/react-native-web#364

When trying to run against [email protected], it looks like:

Error: Cannot find module 'react-dom/lib/EventPluginHub'
    at Function.Module._resolveFilename (module.js:485:15)
    at Function.Module._load (module.js:437:25)
    at Module.require (module.js:513:17)
    at require (internal/module.js:11:18)
    at Object.<anonymous> (/Users/-/Code/zendesk/protoloop-4/node_modules/react-native-web/dist/modules/injectResponderEventPlugin/index.js:1:83)
    at Module._compile (module.js:569:30)
    at Object.Module._extensions..js (module.js:580:10)
    at Module.load (module.js:503:32)
    at tryModuleLoad (module.js:466:12)
    at Function.Module._load (module.js:458:3)

Clarify differences between `react-primitives` and `reactxp`

ReactXP is a library for cross-platform app development using React and React Native, such as Web, Android, iOS, Windows 10 and it seems that they recently added support for macOS.

My first impression was that both of them are pretty similar because they are libraries cross-platform for building apps. I read a little bit more about them and I think the main differences between them are that react-primitives is focused on building just the interface across targets while reactxp is focused on cross-platform app development with all the app logic included. And, of course, the targets/platforms between them are not the same at this point in time.

I would like that someone could clarify this more to have a better understanding and tell me if I am right or wrong. I would appreciate it because, maybe, the differences between them are bigger that I expected them.

Thanks for this amazing library!

Navigate with react-navigation

Hey,

So navigation has been a challenge since the beginning of times in react and I have to say that having primitives is a great idea and in a not far future it hopefully becames a path to follow for all cross platform react developers.

I have started react-navigation-web as an experiment building missing built in views for web, but happy to discuss if possible someway migrate to react-primitives.

Looking for a basic example

Anybody have a basic example? The example/ folder is an example, but its much too difficult for me to understand all the working parts.
I'm wondering if I can use create-react-app & create-reactnative-app w/ styled-components and primitives to create a universal component system. eg) Rendering a H1 on android, web, ios would be very helpful.
Thanks.

Add I18nManager

In order to support RTL layouts, you need to be able to use I18nManager but it is not exported from react-primitives

Animated.View appears to load another version of React.

I'm using react-primitives in a standalone react library. However, I'm unable to import and use the library components in another app since any component that uses Animated.View causes this error to show up:

Uncaught Error: addComponentAsRefTo(...): Only a ReactOwner can have refs. 
You might be adding a ref to a component that was not created inside a component's `render` method, 
or you have multiple copies of React loaded (details: https://fb.me/react-refs-must-have-owner).

Note: other components seem to work fine: if I replace Animated.View with View the error resolves.

Add Icon as a primitive?

Another primitive I see missing is Icon. Icons might be able to be shoehorned into Text or Image primitives however I think that would just muddy them both up.

This one might actually be a bit tricky due to the need to include external fonts. Specifically on React Native requiring a native module when using react-native-vector-icons.

Curious to hear your thoughts on this one @lelandrichardson.

Rename Touchable to Pressable?

This might be just semantics but since Touchable implements onPress and various of "press" methods, maybe it makes more sense for it to be called Pressable?

<Touchable /> is broken (Native)

I cant render any Touchable elements in react-native (using react-primitives or styled-components/primitives

looks like this is the same issue as airbnb/react-sketchapp#104

Code:

import React from 'react'
import { Touchable } from 'react-primitives'
export default () => <Touchable />

Versions:

"react": "16.0.0-alpha.12",
"react-native": "0.45.1",
"react-primitives": "^0.4.3",
"styled-components": "^2.1.0"

Error:
image

Stylesheet specificity and pseudoclasses

It looks like this fix for class specificity:
#37
might need to expand to also handle pseudoclasses and media queries.

If you have a situation like this:

red: {
    backgroundColor: 'red',
    ':first-child': {
        backgroundColor: 'green'
    }
},
blue: {
    backgroundColor: 'blue',
}

<View style={[styles.blue, styles.red]}></View>

It looks like it ends up generating classes that look like this:

.foo1, .foo3.foo3{
    backgroundColor: red;
}
.foo4:first-child{
    background-color: green;
}
.foo2{
    backgroundColor: blue;
}

And so the element styled with foo3 will still be red even if it's the first child due to specificity.

Maybe the solution would be to also include .foo3:first-child in the pseudoclass rule:

.foo1, .foo3.foo3{
    backgroundColor: red;
}
.foo4:first-child.foo4:first-child {
    background-color: green;
}

But I haven't completely thought it through and it has the feeling of getting sucked into a specificity war. Would be curious to hear anyone else's thoughts!

TypeScript Definitions Missing

Currently I can't compile my typescript react project when trying to use the new styled-components/primitives library extension because typings definitions are not present for the react-primitives repository. There is also no @types/react-primitives present either.

Best way to implement react native's TouchableNativeFeedback?

I'm starting to experiment with react-primitives and react-sketchapp, and ideally I'd like to convert some components we've built into using react-primitives so that they can be universally rendered. I'm aware that react-primitives comes with a touchable primitive, but I just noticed that one of the components we're using in our native app right now uses the native TouchableNativeFeedback component in order to correctly display the android specific ripple effect in response to a touch. Is there a way to convert this component using react-primitives, or do I have to abandon the ripple effect and just rely on the touchable in react-primitives?

Why No TextInput Primitive?

I've seen some light discussion on why TextInput may or may not make sense as a primitive. Mostly in this issue.

I too believe that text inputs are a core feature of building complex, rich, interactive UIs. I would like to start a more in-depth discussion on what it would take to add such interactive elements to the core API. Or, to see more insight as to the hesitation against such a move.

Ugify error Expo v19.0.0

Hi,
I'm using react-primitives on Expo v19.0.0 while enabling Minify mode (Uglify). I found that react-primitives cause the error:

Error: Uncaught error in the transformer worker: D:\Office\learn\test\node_modules\metro-bundler\build\transformer.js
    at _transform.then.catch.error (D:\Office\learn\test\node_modules\metro-bundler\build\JSTransformer\index.js:147:31)
    at process._tickCallback (internal/process/next_tick.js:109:7)

This error is gone if you disable Minify mode or remove react-primitives.

You can try by using create-react-native-app

  1. require react-primitives in your code.
  2. enable minify mode by edit setting file in ./.expo/settings.json with:
{
  ...
  "minify": true,
  ...
}
  1. run yarn start or npm start in your command line to start a project
  2. access a project with your phone or access to bundleUrl directly on your browser
  3. error should display on your command line

This error occurs on both platforms.

Differences between sketch and web: misaligned flex boxes

I'm rendering rows that all have equal width cells using flex: 1. The problem is on the web, if the cell has content, the width is not the same as the cells in other rows and it becomes misaligned. Full code to reproduce is here:

import React from 'react';
import { Text, View } from 'react-primitives';

function Row({ children }) {
  return (
    <View style={{ flexDirection: 'row', height: 50 }}>
      <View style={{ borderWidth: 1, borderColor: '#f0f0f0', flex: 1 }} />
      <View style={{ borderWidth: 1, borderColor: '#f0f0f0', flex: 1 }}>
        {children}
      </View>
      <View style={{ borderWidth: 1, borderColor: '#f0f0f0', flex: 1 }} />
      <View style={{ borderWidth: 1, borderColor: '#f0f0f0', flex: 1 }} />
    </View>
  );
}

function Document() {
  return (
    <View style={{ width: 500 }}>
      <Row>hello</Row>
      <Row />
      <Row />
      <Row />
      <Row />
    </View>
  );
}

export default Document;

If you render this in sketch it looks like this, which is correct:

screen shot 2017-05-15 at 12 27 14 pm

However, rendering on the web shows this:

screen shot 2017-05-15 at 12 27 48 pm

It's clearly a difference in how flex is treated, but I'd like to know why and if there's any way react-primitives can make it more consistent.

RFC: React Cross-Platform Strategy

to: @necolas

This is mostly in response to #31, but also just something I've been thinking about for some time, and is a proposal for a path to building a real production-quality ecosystem for building UI with React across multiple platforms in a single code base.

At the moment this isn't very easy, and there's no standard or agreed upon way to do it. React Native has been the closest thing to accomplishing this, with the two platforms being iOS and Android platforms (and others in the community sprouting up, such as windows, vr, etc.). Projects like react-primitives and react-native-web are attempting to solve this.

I think it's important to come at this with the angle of it not being just "React Native, but running in a web browser". Similarly, I think it's important to come at this thinking more than just "web" and "native", even if we don't know what all of the additional platforms will be. (Though we can make some educated guesses... Windows, VR, desktop, etc.)

I believe there are three main tenets that are needed to accomplish this:

Three Main Tenets

Tenet 1: Platform Extensions

Platform extensions, such as the ones allowed by the React Native Packager, are crucial to creating cross-platform code-bases. It allows for people to create consistent interfaces with different implementations, and make that transparent to the end user.

I believe we should take this convention a step further by creating a webpack resolver plugin that allows for the exact same resolution rules. Additional plugins for other bundlers such as rollup and browserify would also be ideal.

In addition, I'd like to standardize on a module-scoped package.json directive: platformCascade

In an NPM module's package.json, a library author would be able to describe the proper cascade of platform extensions, and it would be scoped to every file inside of the package, but not in any dependencies. An example platformCascade could be defined in this way:

"platformCascade": {
  "ios": ["ios", "native"],
  "android": ["android", "native"],
  "web": ["web"],
  "sketch": ["sketch"]
},

This allows library authors to define cascades that may not be mainstream (i.e., "sketch"), without it having to be standardized (and without causing unknown side-effects in other modules if that extension just happened to be there).

It is critical that this convention works outside of just the RN packager, as it will be required for this ecosystem to extend beyond just RN and the associated tooling.

Tenet 2: Primitives

In order for cross-platform to really work, we need to make a world where if someone wants to build a cross-platform UI component, they don't have to implement it n times for n platforms. This requires at least a few building block components.

  1. StyleSheet: Layout is critical to building dynamic UIs. There are lots of options for layout algorithms, but flex box makes a compelling choice. Yoga is a cross-platform flex box implementation that will likely be applicable to many platforms, and the algorithm is already available in all major web browsers (though with some problems still remaining). React Native's StyleSheet implementation is quite nice to work with, and works extremely well with React.
  2. View: Basic rectangular view. Important for this to take into account layout (through style) as well as accessibility attributes, and the proper event hooks. The API that RN has chosen for view seems to do a pretty good job, and I suspect this is in large part due to the fact that RN was built with cross-platform in mind.
  3. Text: Laying out text is vital to building UI, obviously.
  4. Image: Sometimes you need to display Images in your UI.
  5. Animated: It's important to make UIs dynamic and interactive. Animation is a critical component to this. The Animated API from React Native is a perfect candidate for this. It is declarative, which makes it easier to decouple the API surface area from platform-specific implementation. It is also already has an implementation completely implemented in JavaScript that would work by default, while other "native" implementations could also be implemented with some effort w/ the same APIs.
  6. Touchable: Touching/Pressing ends up being a fairly basic and essential form of interaction.
  7. Platform: This is less of a primitive as much as it's a utility. Pragmatically speaking, it's often needed to do small statement-level switches between different platforms to configure things differently based on the underlying implementations.

We want to be careful in choosing these "primitives". We need enough to be able to build bigger more complex things, but need to keep it minimal enough so that it's reasonable to expect a new platform to be able to implement the full set of them. I believe things like TextInput may be really important in terms of some platforms, but not others, and so should maybe not be a primitive. This will have to be defined over time, but I think being conservative at first is ideal.

To be honest, I'm actually not sure if I'm even confident about the primitives listed above. For instance, if we wanted to add a platform like "console" and create something like react-curses, it's not clear if Image or Touchable actually make sense. These components were mainly chosen because after creating a fairly complete Component Library for Airbnb in React Native, I noticed that almost 95% of it could be implemented with just these primitives. The four that seem really clear to me are StyleSheet, View, Text, and Platform, but it's a balance.

Tenet 3: Platform built on Primitives

With the "primitives" now built, now it is our job to figure out what useful crap we can build with them! The idea behind the primitives is that they are the building blocks that other more useful things can be built. Perhaps mediocre versions of things that are general and purely implemented by primitives.

Some components will need to have custom platform-specific implementations that will ensure that they perform as good as they possibly can, but we must always have at least one implementation that only uses the primitives (or other higher-order components that themselves have a primitives-only implementation).

There's some obvious candidates for these components. Since we want to be able to share code between React Native and Web, most of the non-platform-specific APIs exported by React Native make obvious choices, but there are obviously lots more.

Proposal

I haven't really proposed anything yet, as much as I've just talked about what I think is important. Here comes the proposal. Please keep in mind that I'm hoping this just starts the conversation. More than anything I'm interested in feedback and seeing if my ideas align with yours.

At the end of the day, I think there'd be a lot of value in us working together, and this is one way I could see that happening while (i hope) serving each of our slightly different use-cases.

The first proposal would be to move/rename necolas/react-native-web to react-community/react-platform. Alternatively, we could deprecate it and start fresh.

react-platform would become a lerna monorepo. One of the packages in the repo would be react-primitives which would include the primitives mentioned above, with the optimal implementation (whether that's RNW's current implementation, or react-primitive's, or some combination of both). The lelandrichardson/react-primitives repo would also be deprecated.

Various modules that have been written in react-native-web would be refactored to be their own package in the lerna monorepo. For instance, ScrollView and ListView would become react-platform-scrollview and react-platform-listview.

A convention I could see working for this monorepo is a folder structure like this:

- react-platform             // repo root directory
  - packages
    - {package-name}
      - {platform-name}
        {file}.js            // clear that files here are meant for {platform}
    {file}.{platform}.js     // optimized version for {platform}
    {file}.js                // fully cross-platform implementation

We could also export a "grab-bag" package which could just be react-platform, which essentially be what react-native-web currently exports (something that attempts to be API-compatible with RN). Of course, you could also keep react-native-web and just depend on all of the corresponding react-platform-* packages or whatever was needed and export them directly (which may actually make more sense?).

Questions & Answers

What packages belong in the react-platform monorepo?

Of course the whole point of this is for any library authors to also be able to publish cross-platform components/modules by only depending on react-primitives and other fully cross-plat dependencies. So packages don't need to be part of the react-platform monorepo in order to be a primitive.

My thinking is that by something being in the monorepo, we are asserting that no matter what platform you are on (i.e., could be something obscure like "sketch"), we are guaranteeing that there will be at least one primitives-only implementation (functional, even if it's not optimal). Of course we will also have more optimized implementations in the case of the more popular platforms (namely, "native" and "web").

How would new platforms get introduced?

I'm still not 100% sure what the right answer here is. If we lived in a world where there were ~15 platforms and there was source code for each in this monorepo, the maintenance burden could start to get out of hand. On the other hand, the idea should be that a new platform need only implement the primitives, and everything else should "just work" (even if using the non-optimal cross-platform implementations). My feeling is that the criteria ought to be something like:

  1. An implementation for every primitive is reasonably complete
  2. Someone is willing to be a point of contact for maintenance / issues / etc.

Does it have to look like React Native's API?

No, but it doesn't hurt if we follow an already existing API, and React Native's make the most sense, as most of them have already been built with cross-platform interfaces in mind.

Will this be maintainable?

Happo is a CI tool built to detect visual regressions by taking screenshots and diffing them. I've been working on getting happo working for iOS, Android, and Sketch as well.

I believe we should be able to create a bunch of minimal examples with the primitives stressing all of the corner cases of layout as well as styling (box shadows, borders, border radius, transforms, etc.).

We then get two things out of this:

  1. We are able to detect visual regressions of the primitives and other components of the platform.
  2. We are able to directly compare all of the platforms in a straightforward way.

This, in addition to standard stuff like tests, listing, etc. I think will give us a pretty good story in terms of maintenance.

Long Term

React Native

Although this wouldn't have to be an initial goal, I could eventually see implementations of various react native APIs moved into the react-platform repo instead of the react-native one. We have already talked about making RN core more modular and moving it into a similar repo structure. It might make sense for some of these things (like ListView, for example) to live outside of ReactNative as a lot of their optimizations are JS-level optimizations and could benefit all platforms.

Flexbox / Yoga

I know that Sebastian Markbage has been thinking about integrating layout into react for a long time. I think this would bode very well for the concept of "primitives" and also ensure that different platforms would be more consistent. The main thing each platform would then have to provide would be a text measurement API. I'd like to add an emscripten pipeline to Yogo so that there is an optimized and consistent JS implementation of flex box that matches the native implementations. You could also see Web Assembly as a target for Yoga in the long term as well.

Adoption

Imagine if today's most popular react-* and react-native-* libraries depended on react-primitives or react-platform-* packages instead of react-native or "host" DOM components like <div> and <span>. Entirely new platforms could be born overnight by just implementing the primitives, and entire code bases could be made to target those platforms with just the changing the "platform" target of your JS bundler, and potentially implementing a couple of platform-specific interfaces where needed.


I look forward to your thoughts, and hope that we can find a time to talk about this more seriously if you are interested (perhaps next React Wednesday?)

Still maintained?

Is this project still active?

There are a few outstanding issues with pull requests open to fix those issues, but no activity from the contributors on either merging them or even rejecting them.

I started building a library of components around react-primitives, mostly because of react-sketchapp support, but also the idea of rendering to multiple platforms from one codebase. Now i'm slightly regretting that choice as it looks like this might be dead?

Error when Touchable is bundled

On web, Touchable errors when react-primitives is bundled with a react component thats then bundled, for instance, as an npm package.

Warning: Unknown event handler property `onStartShouldSetResponder`

Took me a while to prove to myself that it was an issue with react-primitives. I've written a stripped down example repo that reproduces the issue. Heres a direct link to the hypothetical component that would use react-primitives, its a really simple implementation

Repo with bug reproduced

Screenshot:

screenshot of bug

I originally thought this had something to do with react-primitives not being up to date with React 16, and react-dom getting angry about it. Spent a lot of time debugging devDependencies and peerDependencies. Also tweaked and trimmed down my webpack config to try to figure out any bundling issue. I've recreated the issue in that repo using react-primitives at [email protected] and [email protected]. It happens in either version. (I used my PR upgrading react-primitives to React 16 for the example at 16.2.0)

The example repo has a small webpack config for the hypothetical component and a separate webpack config for the example dir showcasing the component's usage. All I've done in the hypothetical component is import Touchable and added a simple View and Text for something to click on. On refresh I get the error output above

Does anyone have any idea what the issue is? Is webpack doing something I'm not seeing?

This is preventing me from using react-primitives in several open source components I'd like to write

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.