GithubHelp home page GithubHelp logo

necolas / react-native-web Goto Github PK

View Code? Open in Web Editor NEW
21.3K 336.0 1.8K 93.18 MB

Cross-platform React UI packages

Home Page: https://necolas.github.io/react-native-web

License: MIT License

JavaScript 82.98% HTML 7.86% CSS 9.12% Shell 0.05%
react react-components gui-framework css-in-js react-native react-native-web cross-platform react-dom react-ui

react-native-web's Introduction

Development monorepo

This is the development monorepo for "React Native for Web" and related projects.

Structure

  • .github
    • Contains workflows used by GitHub Actions.
    • Contains issue templates.
  • configs
    • Contains configuration files used by the monorepo tooling (compiling, linting, testing, etc.)
  • packages
  • scripts
    • Contains Node.js scripts for miscellaneous tasks.

Tasks

  • build
    • Use npm run build to run the build script in every package.
    • Use npm run build -w <package-name> to run the build script for a specific package.
  • dev
    • Use npm run dev to run the dev script in every package.
    • Use npm run dev -w <package-name> to run the dev script for a specific package.
  • test
    • Use npm run test to run tests for every package.

More details can be found in the contributing guide below.

Contributing

Development happens in the open on GitHub and we are grateful for contributions including bugfixes, improvements, and ideas.

Code of conduct

This project expects all participants to adhere to Meta's OSS Code of Conduct. Please read the full text so that you can understand what actions will and will not be tolerated.

Contributing guide

Read the contributing guide to learn about the development process, how to propose bugfixes and improvements, and how to build and test your changes to React Native for Web.

Good first issues

To help you get you familiar with the contribution process, there is a list of good first issues that contain bugs which have a relatively limited scope. This is a great place to get started.

react-native-web's People

Contributors

appden avatar bloodyowl avatar brunolemos avatar comp615 avatar davidrieman avatar dependabot[bot] avatar evanbacon avatar giuseppeg avatar hushicai avatar ijzerenhein avatar intergalacticspacehighway avatar janicduplessis avatar jaulz avatar johakr avatar kristerkari avatar luciochavezfuentes avatar makkarmeenu avatar minishlink avatar moox avatar necolas avatar paularmstrong avatar philipp-spiess avatar pruthvip avatar ral51 avatar sawa-zen avatar slorber avatar tarunrajput avatar vaukalak avatar vincebt avatar yuxizhe 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  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-native-web's Issues

View: perf optimizations for non-Chrome browsers

In non-Chrome browsers, especially Safari, performance is crippled by nested flexbox columns. Performance is not quite so bad, but still bad, when nesting flexbox columns and rows.

It can be worked around by interrupting the chain of nested flexboxes with an element that is not display:flex. This is bad news for flexGrow:1 propagation. I wonder if RNW could determining when it is safe to insert a non-flex wrapper (i.e., when there's no use of flex-* sizing properties on child elements). Could also log a warning when we know there is deep nesting.

Ideas for web version of `StyleSheet`

Problems

  1. The current strategy of using a hand-rolled CSS library means that inline styles are used for any app-specific values (e.g., borderColor: 'orange').
  2. The hand-rolled library adds ~8KB to the gzipped size of the module. About 5KB is the CSS string, with the rest coming from the strings in the precomputed dictionary (using to map inline styles to class names)
  3. There are cases where specificity bugs can result with shorthands, because some styles exist as classes but others end up as inline styles. For example: { border: 4, borderBottom: 0 } => <div class="borderBottom-0" style="border: 4px"> – the bottom border remains 4px.
  4. There's no StyleSheet.create shim.

Possible solution 1

This describes a solution I hacked together this afternoon, minus the CSS vendor prefixing.

Make StyleSheet.create return the object of styles untouched:

const StylesSheet = {
  create: (style: Object): Object => {
    // do things
    return style
  }
}

The React Component code remains the same, styles are plain objects that can be used as if they were inline styles. Rules can be nested. React's style prop is not overloaded to accept arrays.

import React, { StyleSheet, View } from 'react-native-web'

const styles = StyleSheet.create({
  resizeMode: {
    contain: { backgroundSize: 'contain' },
    cover: { backgroundSize: 'cover' }
  },
  rounded: {
    borderRadius: 50
  }
})

export default const Example = ({ resizeMode, rounded }) => (
  <View style={
    ...styles.resizeMode[resizeMode],
    (rounded && styles.rounded)
  } />
)

create keeps track of every unique style declaration it sees, and generates a dictionary of declarations to unique class names.

{
  'border: 1px 2px 3px 4px': '_rn02',
  'margin: 0 auto': '_rn01',
}

StyleSheet converts these unique declarations to vendor prefixed CSS code. When the app initializes in the browser, this is inserted into the head as a tracked style element. For server-side rendering something like StyleSheet.renderToString can be used to prerender the styles into the head.

CoreComponent replaces the current style dictionary with the one dynamically created by, and retrieved from StyleSheet.

Result

  • Minimal inline style use in the browser.
  • The vast majority of unique declarations are now backed by class names, only the unique declarations created outside of StyleSheet.create end up as inline styles.
  • Produces pretty much the least amount of CSS possible for the application UI. No specificity issues due to declaration-based selectors.
  • No build step (maybe also a downside). There is no CSS to extract, it's generated at run time from the imported modules.
  • You are still working with JS objects (divergence from React Native).
  • Works with 0.14 stateless function components.
  • Should support code-splitting by updating the injected <style> when new bundles are downloaded.
  • Unlike css-loader strategies, the mapping is dynamic so we can produce any declarations from a fixed amount of code (rather than adding static lookup dictionaries for each new component).

Drawbacks

  • All CSS prefixing must be done in react-native-web (must include all browser prefixed for server-side rendering case)
  • Need to add units to some number values
  • ?

cc @vjeux is this stupid? also, this project is fun, but am I wasting my time if you're making a web backend at Facebook?

Configurable styling strategy

What if the style strategy could be configured in the project entry file? You could opt in to the precomputed library, or go with pure inline styles, or maybe even drop in a different strategy.

Touchable: comparison with RN components?

How similar to RN does this need to be? What have I overlooked about the decisions behind the RN components? Should the RN components be provided by this package? Is it a problem to introduce Web divergences given that RN already has many Android/iOS-only props and components?

The Touchable component API's in RN were the ones I felt least happy about.

  1. Not obvious why there needs to be multiple Touchable components with such similar APIs. Why don't they all have a style prop? Why is accessibilityLabel missing from props?
  2. Felt confusing that some Touchable components accept single vs multiple children.
  3. Felt like slightly inconsistent prop names: activeOpacity vs underlayColor, even though they are both only in effect when "active".
  4. Looks like you could use onPress* callbacks to achieve the same outcome as onShowUnderlay and onHideUnderlay.

The implementations themselves are more complex and comprehensive than what's here so far, and the particularities of the native platforms escape me…so I've probably overlooked some key details. But what I did was:

  1. Rolled them all into a single Touchable component, added accessibilityLabel and style props.
  2. Only accept a single child (I think Web could accept multiple children though, with a modified implementation),
  3. underlayColor -> activeUnderlayColor
  4. Didn't include onShow/HideUnderlay.

And I assumed that anyone using with RN at this early stage could create comparable aliases from RNW's Touchable, for example:

var TouchableWithoutFeedback = (props) => (
  <Touchable {...props} activeUnderlayColor='transparent' activeOpacity={1} style={} />
)

var TouchableOpacity = (props) => (
  <Touchable {...props} activeUnderlayColor='transparent' style={} />
)

var TouchableHighlight = (props) => (
  <Touchable {...props}
    activeUnderlayColor={props.underlayColor}
    onPressIn={(...args) => {props.onPressIn(..args) && props.onShowUnderlay(...args)}}
    onPressOut={(...args) => {props.onPressOut(..args) && props.onHideUnderlay(...args)}}
  />
)

cc @vjeux

SDK components to use specific classes?

For all the SDK components – View, Text, Image – it might be less noisy (since they get used everywhere) to wrap their default styles up in a single class.

Links: new component for web or add `href` prop?

The project currently includes an undocumented hack of sorts for anchors: using accessibilityRole='link' +href(undocumented prop / all unknown props are passed through). I think it would be preferable not to pass through unknown props (other than perhapsaria` for now) so that means either:

  1. Add href prop to View, Text, and Touchable
  2. Create a Link component based on Text

This issue isn't really encountered if using react-router because it provides its own Link, but it might also be useful to port the react-router Link component (as a separate module) so the styles can be prefixed and className-ified.

Navigator

web version of react-navigator - https://github.com/bh5-js/react-navigator

can we add this as dependency and expose via react-native-web ?

or can we copy the source to navigator folder( ofc if author of bh-react-navigator agree only) ?

WDYT ..

Add FAQ to README

Move section of media queries to FAQs, and answer questions:

  • what is the project aim?
  • how does it relate to React Native?
  • what are the benefits of this over something like Radium or CSS modules?
  • has this been validated in a real app ;)
  • what is the roadmap?

TextInput: setting selection state

TextInput on web includes onSelectionChange (not yet in the OSS version of React Native). Setting the selection state is a common use case, e.g., moving the cursor to the end of the existing value. DOM API: setSelectionRange

Maybe something like this:

<TextInput
  initialSelection={
    (value) => ({ selectionStart: value.length, selectionEnd: value.length })
  }
/>

Remove `component` prop

Problem

The component prop is a very web-specific feature and hole in the abstractions. When I first implemented View and Text in a mobile codebase at Twitter, this prop got badly named element because it was intended to set the HTML tag name of the resulting DOM node. It was adapted to support components and allow this kind of basic pattern:

import { Link } from 'react-router'

const MyComponent = () => <Text component={Link} to="/" size="large">Home</Text>

The idea of setting the HTML tag name was carried over to this implementation. But after implementing the core accessibility props – accessible, accessibilityLabel, and the introduction of accessibilityRole – and writing some components, I found myself either not using component in favour of the more semantic accessibilityRole, or setting them both to the same value.

Solution

@sebmarkbage and @vjeux have been tweeting related thoughts the last few days (e.g., https://twitter.com/sebmarkbage/status/646770556642045952) and Chrome's native elements have long been making heavy use of ARIA in their shadow dom implementation.

So dropping component fixes the above problems. The accessibility props can be used to provide rich semantics and accessibility annotations. We can also map the role to an HTML element (<View accessibilityRole="main" /> => <main role='main' />) to provide improved legacy support for AT like JAWS.

StyleSheet: fix 'process.env.NODE_ENV' check

I think this is because webpack is being used to bundle the modules for publishing, and seems to prevent the variable replacement in an app. Fix should be to use babel to transpile the modules but not build them into a bundle.

Accessibility props

React Native has a few accessibility-related props. Web accessibility can be backed by ARIA states and properties and ARIA roles.

React Native

  • accessible: bool
  • accessibilityLabel: string
  • accessibilityLiveRegion (Android): oneOf
  • accessibilityTraits (iOS) / accessibilityComponentType (Android): oneOf
  • importantForAccessibility (Android): oneOf

React Native Web

  • accessible: bool (using aria-hidden)
  • accessibilityLabel: string (using aria-label)
  • accessibilityLiveRegion oneOf (using aria-live)
  • accessibilityRole oneOf (using ARIA role)

The accessibilityRole prop would be a platform-specific prop (comparable to accessibilityTraits) with any values defined for ARIA role.

The View component passes all unspecified props to the resulting DOM node, which means that all ARIA properties can be used directly for more complex accessibility patterns that may be required in custom component implementations (e.g., checkboxes, menus, control panels).

Support Navigator?

From the docs:

Use Navigator to transition between different scenes in your app. To accomplish this, provide route objects to the navigator to identify each scene, and also a renderScene function that the navigator can use to render the scene for a given route.

Should the project have Navigator?

StyleSheet: shorthand properties overriding specific values

Example:

const style = StyleSheet.create({
  root: {
    borderStyle: 'none',
    borderBottomStyle: 'solid'
  }
})

The generated CSS depends on alpha-sorting style properties, so the borderStyle rule comes after borderBottomStyle and means the second style is never applied.

Options:

  1. Redo the logic, probably to expand shorthand styles. At the least, the sorting needs to be fixed as alpha-sort places shorthands after longhands for some properties.
  2. Do not respect order of styles (i.e., it doesn't work like CSS)

Extracting the CSS file

The package is current distributed with the CSS inline, and it gets written into the document head. For server-side renders, it would be better to extract the CSS so its available before the JS is downloaded and executed. It's also a small and highly cachable file, that some apps might want to inline on initial request.

Perhaps distribute 2 builds? One with CSS injected, the other as an external stylesheet

remove react dependency?

In my react 0.14 app when i install react-native-web, app is not working ..

Uncaught Error: Invariant Violation: View.render(): A valid ReactComponent must be returned. You may have returned undefined, an array or some other invalid object

StyleSheet: investigate support for code-splitting

Large apps use code-splitting to async or lazy load bundles. At the moment, any unique declarations defined in those bundles will not be represented in the CSS style sheet (but will fall back to inline styles). We should probably re-render the existing stylesheet; that might mean moving the client-side element render into StyleSheet and working out when to trigger a re-render.

Problem: some dependencies have no unit tests

react-tappable and react-textarea-autosize were used to bootstrap Touchable and TextInput respectively, but neither has test coverage. Consider adapting those implementations for react-native-web and adding tests.

Should 'react' and 'react-dom' be bundled by default?

React Native bundles a (forked) version of React with each release. That strategy would reduce compatibility issues between this framework and versions of React (as well as fewer packages to install). If this project were to do the same, it might make it a bit more complicated to determine which other react-* packages are compatible with a release though. That's probably the main reason I've avoided doing so for now.

Another option the bundling of react packages would provide is the ability to provide render methods that take care of the stylesheet creation.

TextInput: support `outline`

When using <TextInput>, I'd like to be able to disable the default blue outline added by Chrome. However, React Native's TextInput doesn't support this property. I have a few possible solutions for the problem:

  • Provide the ability to customize this property, even though it's not present in React Native
  • Use external CSS stylesheets
  • Reset it in react-native-web and don't allow any customization

StyleSheet: add support for 'boxShadow'

Not sure what to do about this. React Native adds shadow properties:

shadowColor
shadowOffset
shadowOpacity
shadowRadius

Web has box-shadow, and it supports multiple shadows.

blurRadius
color
inset
offsetX
offsetY
spreadRadius

I can't see a clear mapping between the two. At least for now we can add boxShadow: string as another web-specific style prop.

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.