diff --git a/.eslintrc b/.eslintrc index 53e0250bca..4b8b43b432 100644 --- a/.eslintrc +++ b/.eslintrc @@ -118,7 +118,7 @@ "no-with": 2, "prefer-const": 2, "prefer-rest-params": 2, - "quotes": [2, "single", "avoid-escape"], + "quotes": [2, "single", { "avoidEscape": true, "allowTemplateLiterals": true }], "radix": 2, "use-isnan": 2, "valid-typeof": 2, diff --git a/.flowconfig b/.flowconfig index f70d341819..407b75d42b 100644 --- a/.flowconfig +++ b/.flowconfig @@ -1,11 +1,12 @@ [version] -^0.148.0 +0.148.0 [ignore] /.*/__tests__/.* /packages/.*/dist/.* /packages/docs/.* /packages/examples/.* +.*/node_modules/.*/.*.json .*/node_modules/@emotion/css/* .*/node_modules/babel-plugin-transform-react-remove-prop-types/* diff --git a/LICENSE b/LICENSE index 7ba8a3821b..c9e1b5a96c 100644 --- a/LICENSE +++ b/LICENSE @@ -1,7 +1,7 @@ MIT License -Copyright (c) 2015-present, Nicolas Gallagher. -Copyright (c) 2015-present, Facebook, Inc. +Copyright (c) Nicolas Gallagher. +Copyright (c) Meta Platforms, Inc. and affiliates. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index d0137e85ec..cd5d648cc1 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ The main purpose of this repository is to help evolve React web and native devel ### Code of conduct -Facebook has adopted a [Code of Conduct][code-of-conduct] that this project expects all participants to adhere to. Please read the full text so that you can understand what actions will and will not be tolerated. +Meta has adopted a [Code of Conduct][code-of-conduct] that this project expects all participants to adhere to. Please read the full text so that you can understand what actions will and will not be tolerated. ### Contributing guide @@ -63,7 +63,7 @@ React Native for Web is [MIT licensed](./LICENSE). By contributing to React Nati [package-url]: https://www.npmjs.com/package/react-native-web [ci-badge]: https://github.com/necolas/react-native-web/workflows/tests/badge.svg [ci-url]: https://github.com/necolas/react-native-web/actions -[react-native-url]: https://facebook.github.io/react-native/ +[react-native-url]: https://reactnative.dev/ [contributing-url]: https://github.com/necolas/react-native-web/blob/master/.github/CONTRIBUTING.md [good-first-issue-url]: https://github.com/necolas/react-native-web/labels/good%20first%20issue -[code-of-conduct]: https://code.facebook.com/codeofconduct +[code-of-conduct]: https://opensource.fb.com/code-of-conduct/ diff --git a/flow-typed/npm/styleq.js b/flow-typed/npm/styleq.js new file mode 100644 index 0000000000..c3715dc900 --- /dev/null +++ b/flow-typed/npm/styleq.js @@ -0,0 +1,40 @@ +type CompiledStyle = { + $$css: boolean, + [key: string]: string, +}; + +type InlineStyle = { + [key: string]: mixed, +}; + +type EitherStyle = CompiledStyle | InlineStyle; + +type StylesArray<+T> = T | $ReadOnlyArray>; +type Styles = StylesArray; +type Style<+T = EitherStyle> = StylesArray; + +type StyleqOptions = { + disableCache?: boolean, + disableMix?: boolean, + transform?: (EitherStyle) => EitherStyle, +}; + +type StyleqResult = [string, InlineStyle | null]; +type Styleq = (styles: Styles) => StyleqResult; + +type IStyleq = { + (...styles: $ReadOnlyArray): StyleqResult, + factory: (options?: StyleqOptions) => Styleq, +}; + +declare module "styleq" { + declare module.exports: { + styleq: IStyleq + }; +} + +declare module "styleq/transform-localize-style" { + declare module.exports: { + localizeStyle: (style: EitherStyle, isRTL: boolean) => EitherStyle + }; +} diff --git a/package.json b/package.json index 8d4f3bf75d..785c5e1ead 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,9 @@ "flow": "flow", "fmt": "prettier --write \"**/*.js\"", "fmt:report": "prettier --check \"**/*.js\"", - "jest": "jest --config ./scripts/jest/config.js", + "jest": "npm-run-all \"jest:* {@}\" --", + "jest:dom": "jest --config ./scripts/jest/config.js", + "jest:node": "jest --config ./scripts/jest/config.node.js", "lint": "yarn lint:report --fix", "lint:report": "eslint packages scripts", "prerelease": "yarn test && yarn compile", @@ -39,32 +41,31 @@ "@babel/preset-react": "^7.12.13", "@testing-library/react": "^11.2.5", "babel-eslint": "^10.1.0", - "babel-jest": "^26.6.3", + "babel-jest": "^27.5.1", "babel-loader": "^8.2.2", "babel-plugin-add-module-exports": "^1.0.4", "babel-plugin-transform-react-remove-prop-types": "^0.4.24", "caniuse-api": "^3.0.0", "cross-env": "^7.0.3", - "del-cli": "^3.0.1", + "del-cli": "^4.0.1", "eslint": "^7.19.0", "eslint-config-prettier": "^7.2.0", "eslint-plugin-flowtype": "^5.4.0", "eslint-plugin-promise": "^4.2.1", "eslint-plugin-react": "^7.22.0", "eslint-plugin-react-hooks": "^4.2.0", - "flow-bin": "^0.148.0", + "flow-bin": "0.148.0", "gen-flow-files": "^0.4.11", "glob": "^7.1.6", "husky": "^4.3.8", "inline-style-prefixer": "^6.0.0", - "jest": "^25.5.0", - "jest-canvas-mock": "^2.3.1", + "jest": "^27.5.1", "lint-staged": "^10.5.4", "npm-run-all": "^4.1.3", "prettier": "^2.2.1", - "react": "^17.0.1", - "react-dom": "^17.0.1", - "react-test-renderer": "^17.0.1" + "react": "^17.0.2", + "react-dom": "^17.0.2", + "react-test-renderer": "^17.0.2" }, "workspaces": [ "packages/*" diff --git a/packages/babel-plugin-react-native-web/src/moduleMap.js b/packages/babel-plugin-react-native-web/src/moduleMap.js index 5f524da385..d33577a4d5 100644 --- a/packages/babel-plugin-react-native-web/src/moduleMap.js +++ b/packages/babel-plugin-react-native-web/src/moduleMap.js @@ -67,5 +67,6 @@ module.exports = { render: true, unmountComponentAtNode: true, useColorScheme: true, + useLocaleContext: true, useWindowDimensions: true }; diff --git a/packages/benchmarks/package.json b/packages/benchmarks/package.json index f03a0f2f37..a96450fb72 100644 --- a/packages/benchmarks/package.json +++ b/packages/benchmarks/package.json @@ -7,13 +7,9 @@ "build": "NODE_ENV=production yarn dev" }, "dependencies": { - "aphrodite": "^2.4.0", - "classnames": "^2.2.6", + "classnames": "^2.3.1", "d3-scale-chromatic": "^2.0.0", - "@emotion/css": "^11.1.3", - "react-jss": "^10.5.1", - "react-native-web": "0.17.7", - "styled-components": "^5.2.1" + "react-native-web": "0.17.7" }, "devDependencies": { "babel-plugin-react-native-web": "0.17.7", diff --git a/packages/benchmarks/src/app/App.js b/packages/benchmarks/src/app/App.js index 4af159439b..31ad1d7fab 100644 --- a/packages/benchmarks/src/app/App.js +++ b/packages/benchmarks/src/app/App.js @@ -169,7 +169,7 @@ export default class App extends Component { () => ({ status: 'running' }), () => { if (this._shouldHideBenchmark && this._benchWrapperRef) { - this._benchWrapperRef.setNativeProps({ style: { opacity: 0 } }); + this._benchWrapperRef.style.opacity = 0; } this._benchmarkRef.start(); this._scrollToEnd(); @@ -181,9 +181,7 @@ export default class App extends Component { _handleVisuallyHideBenchmark = () => { this._shouldHideBenchmark = !this._shouldHideBenchmark; if (this._benchWrapperRef) { - this._benchWrapperRef.setNativeProps({ - style: { opacity: this._shouldHideBenchmark ? 0 : 1 } - }); + this._benchWrapperRef.style.opacity = this._shouldHideBenchmark ? 0 : 1; } }; diff --git a/packages/benchmarks/src/app/Icons.js b/packages/benchmarks/src/app/Icons.js index a5fb9e99b4..c665a05e72 100644 --- a/packages/benchmarks/src/app/Icons.js +++ b/packages/benchmarks/src/app/Icons.js @@ -15,16 +15,13 @@ const styles = StyleSheet.create({ const createIcon = (children) => { const Icon = (props) => - createElement( - 'svg', - { - style: StyleSheet.compose(styles.root, props.style), - width: 24, - height: 24, - viewBox: '0 0 24 24' - }, - children - ); + createElement('svg', { + children, + style: StyleSheet.compose(styles.root, props.style), + width: 24, + height: 24, + viewBox: '0 0 24 24' + }); return Icon; }; diff --git a/packages/benchmarks/src/app/theme.js b/packages/benchmarks/src/app/theme.js index f1b7416a27..68d7058c81 100644 --- a/packages/benchmarks/src/app/theme.js +++ b/packages/benchmarks/src/app/theme.js @@ -1,8 +1,9 @@ -import { canUseDOM } from 'fbjs/lib/ExecutionEnvironment'; +import ExecutionEnvironment from 'fbjs/lib/ExecutionEnvironment'; import { Dimensions, Platform } from 'react-native'; const baseFontSize = 14; const baseUnit = 1.3125; +const { canUseDOM } = ExecutionEnvironment; const createPlatformLength = (multiplier) => Platform.select({ web: `${multiplier}rem`, default: multiplier * baseFontSize }); diff --git a/packages/benchmarks/src/cases/TextTree.js b/packages/benchmarks/src/cases/TextTree.js deleted file mode 100644 index 5324a3bdad..0000000000 --- a/packages/benchmarks/src/cases/TextTree.js +++ /dev/null @@ -1,36 +0,0 @@ -import { BenchmarkType } from '../app/Benchmark'; -import React, { Component } from 'react'; - -class TextTree extends Component { - static displayName = 'TextTree'; - - static benchmarkType = BenchmarkType.MOUNT; - - render() { - const { breadth, components, depth, id, wrap } = this.props; - const { TextBox } = components; - - let result = ( - - {depth === 0 && } - {depth !== 0 && - Array.from({ length: breadth }).map((el, i) => ( - - ))} - - ); - for (let i = 0; i < wrap; i++) { - result = {result}; - } - return result; - } -} - -export default TextTree; diff --git a/packages/benchmarks/src/impl.js b/packages/benchmarks/src/impl.js index b926c25f8f..fcf6226fd7 100644 --- a/packages/benchmarks/src/impl.js +++ b/packages/benchmarks/src/impl.js @@ -10,7 +10,6 @@ type ComponentsType = { Box: Component, Dot: Component, Provider: Component, - TextBox: Component, View: Component }; diff --git a/packages/benchmarks/src/implementations/aphrodite/View.js b/packages/benchmarks/src/implementations/aphrodite/View.js deleted file mode 100644 index bb2791c250..0000000000 --- a/packages/benchmarks/src/implementations/aphrodite/View.js +++ /dev/null @@ -1,30 +0,0 @@ -import React from 'react'; -import { css, StyleSheet } from 'aphrodite'; - -class View extends React.Component { - render() { - const { style, ...other } = this.props; - return
; - } -} - -const styles = StyleSheet.create({ - root: { - alignItems: 'stretch', - borderWidth: 0, - borderStyle: 'solid', - boxSizing: 'border-box', - display: 'flex', - flexBasis: 'auto', - flexDirection: 'column', - flexShrink: 0, - margin: 0, - padding: 0, - position: 'relative', - // fix flexbox bugs - minHeight: 0, - minWidth: 0 - } -}); - -export default View; diff --git a/packages/benchmarks/src/implementations/aphrodite/index.js b/packages/benchmarks/src/implementations/aphrodite/index.js deleted file mode 100644 index 5a9541d887..0000000000 --- a/packages/benchmarks/src/implementations/aphrodite/index.js +++ /dev/null @@ -1,9 +0,0 @@ -import Box from './Box'; -import Provider from './Provider'; -import View from './View'; - -export default { - Box, - Provider, - View -}; diff --git a/packages/benchmarks/src/implementations/css-modules/Dot.js b/packages/benchmarks/src/implementations/css-modules/Dot.js new file mode 100644 index 0000000000..0300337212 --- /dev/null +++ b/packages/benchmarks/src/implementations/css-modules/Dot.js @@ -0,0 +1,20 @@ +import React from 'react'; +import styles from './dot-styles.css'; + +const Dot = ({ size, x, y, children, color }) => ( +
+ {children} +
+); + +export default Dot; diff --git a/packages/benchmarks/src/implementations/css-modules/dot-styles.css b/packages/benchmarks/src/implementations/css-modules/dot-styles.css new file mode 100644 index 0000000000..6e392563a6 --- /dev/null +++ b/packages/benchmarks/src/implementations/css-modules/dot-styles.css @@ -0,0 +1,10 @@ +.root { + position: absolute; + cursor: pointer; + width: 0; + height: 0; + border-color: transparent; + border-style: solid; + border-top-width: 0; + transform: translate(50%, 50%); +} diff --git a/packages/benchmarks/src/implementations/css-modules/index.js b/packages/benchmarks/src/implementations/css-modules/index.js index 5a9541d887..f32ff155d7 100644 --- a/packages/benchmarks/src/implementations/css-modules/index.js +++ b/packages/benchmarks/src/implementations/css-modules/index.js @@ -1,9 +1,11 @@ import Box from './Box'; +import Dot from './Dot'; import Provider from './Provider'; import View from './View'; export default { Box, + Dot, Provider, View }; diff --git a/packages/benchmarks/src/implementations/css-modules/view-styles.css b/packages/benchmarks/src/implementations/css-modules/view-styles.css index 2dda1491fd..eab671c1eb 100644 --- a/packages/benchmarks/src/implementations/css-modules/view-styles.css +++ b/packages/benchmarks/src/implementations/css-modules/view-styles.css @@ -1,5 +1,6 @@ .initial { align-items: stretch; + background-color: transparent; border-width: 0; border-style: solid; box-sizing: border-box; @@ -7,9 +8,11 @@ flex-basis: auto; flex-direction: column; flex-shrink: 0; + list-style: none; margin: 0; - padding: 0; - position: relative; min-height: 0; min-width: 0; + padding: 0; + position: relative; + z-index: 0; } diff --git a/packages/benchmarks/src/implementations/emotion/Dot.js b/packages/benchmarks/src/implementations/emotion/Dot.js deleted file mode 100644 index 8f2fbe4a04..0000000000 --- a/packages/benchmarks/src/implementations/emotion/Dot.js +++ /dev/null @@ -1,35 +0,0 @@ -import React from 'react'; -import { css } from '@emotion/css'; - -const Dot = ({ size, x, y, children, color }) => ( -
- {children} -
-); - -const styles = { - root: { - position: 'absolute', - cursor: 'pointer', - width: 0, - height: 0, - borderColor: 'transparent', - borderStyle: 'solid', - borderTopWidth: 0, - transform: 'translate(50%, 50%)' - } -}; - -export default Dot; diff --git a/packages/benchmarks/src/implementations/emotion/View.js b/packages/benchmarks/src/implementations/emotion/View.js deleted file mode 100644 index 126f5afe3d..0000000000 --- a/packages/benchmarks/src/implementations/emotion/View.js +++ /dev/null @@ -1,28 +0,0 @@ -import { css } from '@emotion/css'; -import React from 'react'; - -class View extends React.Component { - render() { - const { style, ...other } = this.props; - return
; - } -} - -const viewStyle = { - alignItems: 'stretch', - borderWidth: 0, - borderStyle: 'solid', - boxSizing: 'border-box', - display: 'flex', - flexBasis: 'auto', - flexDirection: 'column', - flexShrink: 0, - margin: 0, - padding: 0, - position: 'relative', - // fix flexbox bugs - minHeight: 0, - minWidth: 0 -}; - -export default View; diff --git a/packages/benchmarks/src/implementations/inline-styles/Dot.js b/packages/benchmarks/src/implementations/inline-styles/Dot.js index 13eec8d821..4a6e4ab776 100644 --- a/packages/benchmarks/src/implementations/inline-styles/Dot.js +++ b/packages/benchmarks/src/implementations/inline-styles/Dot.js @@ -2,17 +2,14 @@ import React from 'react'; const Dot = ({ size, x, y, children, color }) => (
{children}
diff --git a/packages/benchmarks/src/implementations/inline-styles/View.js b/packages/benchmarks/src/implementations/inline-styles/View.js index 96ff0dbac8..2768ed39c9 100644 --- a/packages/benchmarks/src/implementations/inline-styles/View.js +++ b/packages/benchmarks/src/implementations/inline-styles/View.js @@ -17,19 +17,20 @@ class View extends React.Component { const viewStyle = { alignItems: 'stretch', - borderWidth: 0, - borderStyle: 'solid', + backgroundColor: 'transparent', + border: '0 solid black', boxSizing: 'border-box', display: 'flex', flexBasis: 'auto', flexDirection: 'column', flexShrink: 0, + listStyle: 'none', margin: 0, + minHeight: 0, + minWidth: 0, padding: 0, position: 'relative', - // fix flexbox bugs - minHeight: 0, - minWidth: 0 + zIndex: 0 }; export default View; diff --git a/packages/benchmarks/src/implementations/react-jss/Box.js b/packages/benchmarks/src/implementations/react-jss/Box.js deleted file mode 100644 index e48d417f1e..0000000000 --- a/packages/benchmarks/src/implementations/react-jss/Box.js +++ /dev/null @@ -1,50 +0,0 @@ -import classnames from 'classnames'; -import injectSheet from 'react-jss'; -import React from 'react'; -import View from './View'; - -const Box = ({ classes, color, fixed = false, layout = 'column', outer = false, ...other }) => ( - -); - -const styles = { - outer: { - alignSelf: 'flex-start', - padding: 4 - }, - row: { - flexDirection: 'row' - }, - color0: { - backgroundColor: '#14171A' - }, - color1: { - backgroundColor: '#AAB8C2' - }, - color2: { - backgroundColor: '#E6ECF0' - }, - color3: { - backgroundColor: '#FFAD1F' - }, - color4: { - backgroundColor: '#F45D22' - }, - color5: { - backgroundColor: '#E0245E' - }, - fixed: { - width: 6, - height: 6 - } -}; - -export default injectSheet(styles)(Box); diff --git a/packages/benchmarks/src/implementations/react-jss/Dot.js b/packages/benchmarks/src/implementations/react-jss/Dot.js deleted file mode 100644 index 568bf60b14..0000000000 --- a/packages/benchmarks/src/implementations/react-jss/Dot.js +++ /dev/null @@ -1,25 +0,0 @@ -import injectSheet from 'react-jss'; -import React from 'react'; - -const Dot = ({ classes, children }) =>
{children}
; - -const styles = { - root: { - position: 'absolute', - cursor: 'pointer', - width: 0, - height: 0, - borderColor: 'transparent', - borderStyle: 'solid', - borderTopWidth: 0, - transform: 'translate(50%, 50%)', - borderBottomColor: ({ color }) => color, - borderRightWidth: ({ size }) => size / 2, - borderBottomWidth: ({ size }) => size / 2, - borderLeftWidth: ({ size }) => size / 2, - marginLeft: ({ x }) => x, - marginTop: ({ y }) => y - } -}; - -export default injectSheet(styles)(Dot); diff --git a/packages/benchmarks/src/implementations/react-jss/Provider.js b/packages/benchmarks/src/implementations/react-jss/Provider.js deleted file mode 100644 index 864fc43a76..0000000000 --- a/packages/benchmarks/src/implementations/react-jss/Provider.js +++ /dev/null @@ -1,2 +0,0 @@ -import View from './View'; -export default View; diff --git a/packages/benchmarks/src/implementations/react-jss/View.js b/packages/benchmarks/src/implementations/react-jss/View.js deleted file mode 100644 index 5a17abc56b..0000000000 --- a/packages/benchmarks/src/implementations/react-jss/View.js +++ /dev/null @@ -1,31 +0,0 @@ -import classnames from 'classnames'; -import injectSheet from 'react-jss'; -import React from 'react'; - -class View extends React.Component { - render() { - const { classes, className, ...other } = this.props; - return
; - } -} - -const styles = { - root: { - alignItems: 'stretch', - borderWidth: 0, - borderStyle: 'solid', - boxSizing: 'border-box', - display: 'flex', - flexBasis: 'auto', - flexDirection: 'column', - flexShrink: 0, - margin: 0, - padding: 0, - position: 'relative', - // fix flexbox bugs - minHeight: 0, - minWidth: 0 - } -}; - -export default injectSheet(styles)(View); diff --git a/packages/benchmarks/src/implementations/react-native-web/TextBox.js b/packages/benchmarks/src/implementations/react-native-web/TextBox.js deleted file mode 100644 index 05d8e6f783..0000000000 --- a/packages/benchmarks/src/implementations/react-native-web/TextBox.js +++ /dev/null @@ -1,38 +0,0 @@ -import React from 'react'; -import { StyleSheet, Text } from 'react-native'; - -const TextBox = ({ color, outer = false, ...other }) => ( - -); - -const styles = StyleSheet.create({ - root: { - color: 'white' - }, - outer: { - fontStyle: 'italic' - }, - row: { - flexDirection: 'row' - }, - color0: { - color: '#14171A' - }, - color1: { - color: '#AAB8C2' - }, - color2: { - color: '#E6ECF0' - }, - color3: { - color: '#FFAD1F' - }, - color4: { - color: '#F45D22' - }, - color5: { - color: '#E0245E' - } -}); - -export default TextBox; diff --git a/packages/benchmarks/src/implementations/react-native-web/index.js b/packages/benchmarks/src/implementations/react-native-web/index.js index 055113c484..0533daaa05 100644 --- a/packages/benchmarks/src/implementations/react-native-web/index.js +++ b/packages/benchmarks/src/implementations/react-native-web/index.js @@ -1,13 +1,11 @@ import Box from './Box'; import Dot from './Dot'; import Provider from './Provider'; -import TextBox from './TextBox'; import { View } from 'react-native'; export default { Box, Dot, Provider, - TextBox, View }; diff --git a/packages/benchmarks/src/implementations/styled-components/Box.js b/packages/benchmarks/src/implementations/styled-components/Box.js deleted file mode 100644 index 97300fcac0..0000000000 --- a/packages/benchmarks/src/implementations/styled-components/Box.js +++ /dev/null @@ -1,31 +0,0 @@ -import styled from 'styled-components'; -import View from './View'; - -const getColor = (color) => { - switch (color) { - case 0: - return '#14171A'; - case 1: - return '#AAB8C2'; - case 2: - return '#E6ECF0'; - case 3: - return '#FFAD1F'; - case 4: - return '#F45D22'; - case 5: - return '#E0245E'; - default: - return 'transparent'; - } -}; - -const Box = styled(View)` - align-self: flex-start; - flex-direction: ${(props) => (props.layout === 'column' ? 'column' : 'row')}; - padding: ${(props) => (props.outer ? '4px' : '0')}; - ${(props) => props.fixed && 'height:6px;'} ${(props) => - props.fixed && 'width:6px;'} background-color: ${(props) => getColor(props.color)}; -`; - -export default Box; diff --git a/packages/benchmarks/src/implementations/styled-components/Dot.js b/packages/benchmarks/src/implementations/styled-components/Dot.js deleted file mode 100644 index 108a0cc107..0000000000 --- a/packages/benchmarks/src/implementations/styled-components/Dot.js +++ /dev/null @@ -1,24 +0,0 @@ -import styled from 'styled-components'; -import View from './View'; - -const Dot = styled(View).attrs((props) => ({ - style: { - marginLeft: `${props.x}px`, - marginTop: `${props.y}px`, - borderRightWidth: `${props.size / 2}px`, - borderBottomWidth: `${props.size / 2}px`, - borderLeftWidth: `${props.size / 2}px`, - borderBottomColor: `${props.color}` - } -}))` - position: absolute; - cursor: pointer; - width: 0; - height: 0; - border-color: transparent; - border-style: solid; - border-top-width: 0; - transform: translate(50%, 50%); -`; - -export default Dot; diff --git a/packages/benchmarks/src/implementations/styled-components/Provider.js b/packages/benchmarks/src/implementations/styled-components/Provider.js deleted file mode 100644 index 864fc43a76..0000000000 --- a/packages/benchmarks/src/implementations/styled-components/Provider.js +++ /dev/null @@ -1,2 +0,0 @@ -import View from './View'; -export default View; diff --git a/packages/benchmarks/src/implementations/styled-components/View.js b/packages/benchmarks/src/implementations/styled-components/View.js deleted file mode 100644 index f0da52e98b..0000000000 --- a/packages/benchmarks/src/implementations/styled-components/View.js +++ /dev/null @@ -1,19 +0,0 @@ -import styled from 'styled-components'; - -const View = styled.div` - align-items: stretch; - border-width: 0; - border-style: solid; - box-sizing: border-box; - display: flex; - flex-basis: auto; - flex-direction: column; - flex-shrink: 0; - margin: 0; - padding: 0; - position: relative; - min-height: 0; - min-width: 0; -`; - -export default View; diff --git a/packages/benchmarks/src/implementations/styled-components/index.js b/packages/benchmarks/src/implementations/styled-components/index.js deleted file mode 100644 index f32ff155d7..0000000000 --- a/packages/benchmarks/src/implementations/styled-components/index.js +++ /dev/null @@ -1,11 +0,0 @@ -import Box from './Box'; -import Dot from './Dot'; -import Provider from './Provider'; -import View from './View'; - -export default { - Box, - Dot, - Provider, - View -}; diff --git a/packages/benchmarks/src/implementations/emotion/Box.js b/packages/benchmarks/src/implementations/styleq/Box.js similarity index 51% rename from packages/benchmarks/src/implementations/emotion/Box.js rename to packages/benchmarks/src/implementations/styleq/Box.js index f3af5dd06a..f5c9eb8df0 100644 --- a/packages/benchmarks/src/implementations/emotion/Box.js +++ b/packages/benchmarks/src/implementations/styleq/Box.js @@ -15,33 +15,42 @@ const Box = ({ color, fixed = false, layout = 'column', outer = false, ...other const styles = { outer: { - alignSelf: 'flex-start', - padding: 4 + $$css: true, + alignSelf: 'r-k200y', + padding: 'r-tuq35u' }, row: { - flexDirection: 'row' + $$css: true, + flexDirection: 'r-18u37iz' }, color0: { - backgroundColor: '#14171A' + $$css: true, + backgroundColor: 'r-1810x6o' }, color1: { - backgroundColor: '#AAB8C2' + $$css: true, + backgroundColor: 'r-dkge59' }, color2: { - backgroundColor: '#E6ECF0' + $$css: true, + backgroundColor: 'r-18z3xeu' }, color3: { - backgroundColor: '#FFAD1F' + $$css: true, + backgroundColor: 'r-1vkxrha' }, color4: { - backgroundColor: '#F45D22' + $$css: true, + backgroundColor: 'r-1dgebii' }, color5: { - backgroundColor: '#E0245E' + $$css: true, + backgroundColor: 'r-e84r5y' }, fixed: { - width: 6, - height: 6 + $$css: true, + width: 'r-8hc5te', + height: 'r-1xbve24' } }; diff --git a/packages/benchmarks/src/implementations/styleq/Dot.js b/packages/benchmarks/src/implementations/styleq/Dot.js new file mode 100644 index 0000000000..d1352fb2c1 --- /dev/null +++ b/packages/benchmarks/src/implementations/styleq/Dot.js @@ -0,0 +1,27 @@ +import React from 'react'; +import { styleq } from 'styleq'; + +const Dot = ({ size, x, y, children, color }) => { + const [className, inlineStyle] = styleq([ + styles.root, + { + borderBottomColor: color, + borderRightWidth: size / 2, + borderBottomWidth: size / 2, + borderLeftWidth: size / 2, + marginLeft: x, + marginTop: y + } + ]); + + return
; +}; + +const styles = { + root: { + $$css: true, + 'css-1co75s2': 'css-1co75s2' + } +}; + +export default Dot; diff --git a/packages/benchmarks/src/implementations/aphrodite/Provider.js b/packages/benchmarks/src/implementations/styleq/Provider.js similarity index 100% rename from packages/benchmarks/src/implementations/aphrodite/Provider.js rename to packages/benchmarks/src/implementations/styleq/Provider.js diff --git a/packages/benchmarks/src/implementations/styleq/View.js b/packages/benchmarks/src/implementations/styleq/View.js new file mode 100644 index 0000000000..46c7495cd1 --- /dev/null +++ b/packages/benchmarks/src/implementations/styleq/View.js @@ -0,0 +1,18 @@ +import React from 'react'; +import { styleq } from 'styleq'; + +const q = styleq.factory({ disableCache: false }); + +function View(props) { + const [className, inlineStyle] = q([styles.root, props.style]); + return
; +} + +const styles = { + root: { + $$css: true, + 'css-175oi2r': 'css-175oi2r' + } +}; + +export default View; diff --git a/packages/benchmarks/src/implementations/emotion/index.js b/packages/benchmarks/src/implementations/styleq/index.js similarity index 100% rename from packages/benchmarks/src/implementations/emotion/index.js rename to packages/benchmarks/src/implementations/styleq/index.js diff --git a/packages/benchmarks/src/implementations/aphrodite/Box.js b/packages/benchmarks/src/implementations/stylesheet/Box.js similarity index 94% rename from packages/benchmarks/src/implementations/aphrodite/Box.js rename to packages/benchmarks/src/implementations/stylesheet/Box.js index 994b956d8d..ad93182e55 100644 --- a/packages/benchmarks/src/implementations/aphrodite/Box.js +++ b/packages/benchmarks/src/implementations/stylesheet/Box.js @@ -1,6 +1,6 @@ import React from 'react'; import View from './View'; -import { StyleSheet } from 'aphrodite'; +import { StyleSheet } from 'react-native-web'; const Box = ({ color, fixed = false, layout = 'column', outer = false, ...other }) => ( { + const [className, inlineStyle] = StyleSheet([ + styles.root$raw, + { + borderBottomColor: color, + borderRightWidth: size / 2, + borderBottomWidth: size / 2, + borderLeftWidth: size / 2, + marginLeft: x, + marginTop: y + } + ]); + + return
; +}; + +const styles = StyleSheet.create({ + root$raw: { + position: 'absolute', + cursor: 'pointer', + width: 0, + height: 0, + borderColor: 'transparent', + borderStyle: 'solid', + borderTopWidth: 0, + transform: 'translateX(50%) translateY(50%)' + } +}); + +export default Dot; diff --git a/packages/benchmarks/src/implementations/emotion/Provider.js b/packages/benchmarks/src/implementations/stylesheet/Provider.js similarity index 100% rename from packages/benchmarks/src/implementations/emotion/Provider.js rename to packages/benchmarks/src/implementations/stylesheet/Provider.js diff --git a/packages/benchmarks/src/implementations/stylesheet/View.js b/packages/benchmarks/src/implementations/stylesheet/View.js new file mode 100644 index 0000000000..96a961a7c8 --- /dev/null +++ b/packages/benchmarks/src/implementations/stylesheet/View.js @@ -0,0 +1,29 @@ +import React from 'react'; +import { StyleSheet } from 'react-native-web'; + +function View(props) { + const [className, inlineStyle] = StyleSheet([styles.root$raw, props.style]); + return
; +} + +const styles = StyleSheet.create({ + root$raw: { + alignItems: 'stretch', + backgroundColor: 'transparent', + border: '0 solid black', + boxSizing: 'border-box', + display: 'flex', + flexBasis: 'auto', + flexDirection: 'column', + flexShrink: 0, + listStyle: 'none', + margin: 0, + minHeight: 0, + minWidth: 0, + padding: 0, + position: 'relative', + zIndex: 0 + } +}); + +export default View; diff --git a/packages/benchmarks/src/implementations/react-jss/index.js b/packages/benchmarks/src/implementations/stylesheet/index.js similarity index 100% rename from packages/benchmarks/src/implementations/react-jss/index.js rename to packages/benchmarks/src/implementations/stylesheet/index.js diff --git a/packages/benchmarks/src/index.js b/packages/benchmarks/src/index.js index 279f247ea3..cd8d37fa9d 100644 --- a/packages/benchmarks/src/index.js +++ b/packages/benchmarks/src/index.js @@ -1,6 +1,5 @@ import App from './app/App'; import impl from './impl'; -import TextTree from './cases/TextTree'; import Tree from './cases/Tree'; import SierpinskiTriangle from './cases/SierpinskiTriangle'; @@ -51,13 +50,6 @@ const tests = { }, Provider: components.Provider, sampleCount: 100 - })), - 'Mount text tree': createTestBlock((components) => ({ - benchmarkType: 'mount', - Component: TextTree, - getComponentProps: () => ({ breadth: 6, components, depth: 3, id: 0, wrap: 2 }), - Provider: components.Provider, - sampleCount: 50 })) }; diff --git a/packages/docs/.eleventy.js b/packages/docs/.eleventy.js index 15df7cc46a..daaffdc1bb 100644 --- a/packages/docs/.eleventy.js +++ b/packages/docs/.eleventy.js @@ -12,7 +12,6 @@ const markdownContainer = require('markdown-it-container'); const markdownEmoji = require('markdown-it-emoji'); const markdownFootnote = require('markdown-it-footnote'); const markdownTasks = require('markdown-it-task-lists'); -const twemoji = require('twemoji'); const UglifyJS = require('uglify-es'); /** @@ -164,11 +163,6 @@ module.exports = function (eleventyConfig) { // https://github.com/revin/markdown-it-task-lists .use(markdownTasks); - // Custom emoji renderer - markdownLib.renderer.rules.emoji = function (token, idx) { - return twemoji.parse(token[idx].content); - }; - eleventyConfig.setLibrary('md', markdownLib); // ELEVENTY CONFIG ----- diff --git a/packages/docs/package.json b/packages/docs/package.json index 4a119446b5..013957b61b 100644 --- a/packages/docs/package.json +++ b/packages/docs/package.json @@ -10,9 +10,9 @@ }, "homepage": "https://github.com/necolas/react-native-web", "devDependencies": { - "@11ty/eleventy": "^0.11.1", - "@11ty/eleventy-navigation": "^0.1.6", - "@11ty/eleventy-plugin-syntaxhighlight": "^3.0.5", + "@11ty/eleventy": "^1.0.0", + "@11ty/eleventy-navigation": "^0.3.2", + "@11ty/eleventy-plugin-syntaxhighlight": "^4.0.0", "csso": "^4.2.0", "eleventy-plugin-svg-contents": "^0.7.0", "eleventy-plugin-toc": "^1.1.0", @@ -25,7 +25,6 @@ "markdown-it-footnote": "^3.0.2", "markdown-it-for-inline": "^0.1.1", "markdown-it-task-lists": "^2.1.1", - "twemoji": "*", "uglify-es": "^3.3.9" } } diff --git a/packages/docs/src/data/site.js b/packages/docs/src/data/site.js index cfdd8a454f..7847b376e9 100644 --- a/packages/docs/src/data/site.js +++ b/packages/docs/src/data/site.js @@ -3,7 +3,7 @@ const packageJson = require('../../package.json'); module.exports = { name: 'React Native for Web', description: '', - footer: 'Copyright © Nicolas Gallagher and Facebook Inc.', + footer: 'Copyright © Nicolas Gallagher and Meta Platforms, Inc.', url: 'https://necolas.github.io/react-native-web', githubUrl: 'https://github.com/necolas/react-native-web', githubBranch: 'master', diff --git a/packages/docs/src/includes/layouts/home.html b/packages/docs/src/includes/layouts/home.html index d7f09a4b64..d99f6faa70 100644 --- a/packages/docs/src/includes/layouts/home.html +++ b/packages/docs/src/includes/layouts/home.html @@ -5,7 +5,7 @@ {% import "fragments/macros.html" as macro with context %} -
+
@@ -40,9 +40,9 @@

React Native Components and APIs on the Web

Try it out!

You can try {{ site.name }} from your browser using the official template on CodeSandbox.

- +

Fork the template and create your own app without leaving the browser.

- +
-

Did you know? React Native for Web is used in production web apps by Twitter, Flipkart, Uber, Major League Soccer, and many others. It also powers web support in multi-platform React projects such as Expo, React Native Elements, React Native Paper, and React Native Base. +

Did you know? React Native for Web is used in production web apps by Twitter, Flipkart, Uber, Major League Soccer, and many others. It also powers web support in multi-platform React projects such as Expo, React Native Elements, React Native Paper, and React Native Base.

- {% include "fragments/footer.html" %} + {% include "fragments/footer.html" %}
diff --git a/packages/docs/src/pages/docs/apis/i18n-manager.md b/packages/docs/src/pages/docs/apis/i18n-manager.md deleted file mode 100644 index d45e3ed288..0000000000 --- a/packages/docs/src/pages/docs/apis/i18n-manager.md +++ /dev/null @@ -1,62 +0,0 @@ ---- -title: I18nManager -date: Last Modified -permalink: /docs/i18n-manager/index.html -eleventyNavigation: - key: I18nManager - parent: APIs ---- - -{% import "fragments/macros.html" as macro with context %} - -:::lead -Control and query the layout and writing direction of the application. -::: - -```js -import { I18nManager } from 'react-native'; -``` - ---- - -## API - -### Static methods - -{% call macro.prop('allowRTL', '(boolean) => void') %} -Allow the application to display in RTL mode. -{% endcall %} - -{% call macro.prop('forceRTL', '(boolean) => void') %} -Force the application to display in RTL mode. -{% endcall %} - -{% call macro.prop('getConstants', '() => I18nConstants') %} -Determine how the application is handling bidi layout. -{% endcall %} - -{% call macro.prop('swapLeftAndRightInRTL', '(boolean) => void') %} -Control whether the application swaps `left`/`right` styles in RTL mode. It is recommended that applications rely on `start`/`end` styles and disable automatic BiDi-flipping of `left`/`right` styles. -{% endcall %} - -{% call macro.prop('setPreferredLanguageRTL', '(boolean) => void') %} -Set the application's preferred writing direction to RTL. You may need to infer the user's preferred locale on the server (from HTTP headers) and decide whether it's an RTL language. (Web-only) -{% endcall %} - -### I18nConstants - -The object returned by `I18nManager.getConstants()`. - -{% call macro.prop('isRTL', 'boolean = false') %} -Whether the application is currently in RTL mode. -{% endcall %} - -{% call macro.prop('doLeftAndRightSwapInRTL', 'boolean = true') %} -Whether the application swaps left/right styles in RTL mode. -{% endcall %} - ---- - -## Examples - -{{ macro.codesandbox('i18n-manager') }} diff --git a/packages/docs/src/pages/docs/apis/linking.md b/packages/docs/src/pages/docs/apis/linking.md index 492ed6d081..de82754d53 100644 --- a/packages/docs/src/pages/docs/apis/linking.md +++ b/packages/docs/src/pages/docs/apis/linking.md @@ -31,8 +31,8 @@ Returns a `Promise` that resolves to a boolean indicating whether the app can op Returns a `Promise` that resolves to the string of the URL that initially loaded the app. {% endcall %} -{% call macro.prop('openURL', '(url) => Promise<>') %} -Try to open the given url in a secure fashion. The method returns a Promise object. If the url opens, the promise is resolved. If not, the promise is rejected. +{% call macro.prop('openURL', '(url, target) => Promise<>') %} +Try to open the given url in a secure fashion. The provided target (including `undefined`) will be passed as the window target, or "_blank" if no target included. The method returns a Promise object. If the url opens, the promise is resolved. If not, the promise is rejected. {% endcall %} --- diff --git a/packages/docs/src/pages/docs/apis/style-sheet.md b/packages/docs/src/pages/docs/apis/style-sheet.md index 468a8683ef..f2ef383fad 100644 --- a/packages/docs/src/pages/docs/apis/style-sheet.md +++ b/packages/docs/src/pages/docs/apis/style-sheet.md @@ -5,6 +5,7 @@ permalink: /docs/style-sheet/index.html eleventyNavigation: key: StyleSheet parent: APIs + label: "Change" --- {% import "fragments/macros.html" as macro with context %} @@ -48,9 +49,9 @@ Combines two styles such that the last style overrides properties of the first s {% endcall %} {% call macro.prop('create', '({ [key]: ruleset }) => ({ [key]: number })') %} -Define style objects. Each key of the object passed to `create` must define a style object. These values are opaque and should not be introspected. +Define style objects. Each key of the object passed to `create` must define a style object. These values should not be introspected at runtime. {% endcall %} {% call macro.prop('flatten', '(styles: Style) => Object') %} -Lookup a style object by ID or flatten an array of styles into a single style object. +Flatten an array of styles into a single style object. **This is not recommended as it is not compatible with static extraction of styles to CSS.** {% endcall %} diff --git a/packages/docs/src/pages/docs/appendix/about-project.md b/packages/docs/src/pages/docs/appendix/about-project.md index 15af20a361..f0b9c9b05a 100644 --- a/packages/docs/src/pages/docs/appendix/about-project.md +++ b/packages/docs/src/pages/docs/appendix/about-project.md @@ -15,7 +15,7 @@ eleventyNavigation: {{ site.name }} was started in 2015 by [Nicolas Gallagher](http://nicolasgallagher.com) during the development of [Twitter's Progressive Web App](https://blog.twitter.com/engineering/en_us/topics/open-source/2017/how-we-built-twitter-lite.html). It has evolved from a framework inspired by React Native into a mature and pragmatic compatibility layer between React DOM and React Native. -{{ site.name }} is currently used in production Web apps by companies including [Twitter](https://twitter.com), [Flipkart](https://twitter.com/naqvitalha/status/969577892991549440), [Uber](https://www.youtube.com/watch?v=RV9rxrNIxnY), and [Major League Soccer](https://matchcenter.mlssoccer.com). Software engineers from Facebook, Twitter, and Expo continue to contribute design and patches to the project. +{{ site.name }} is currently used in production Web apps by companies including [Twitter](https://twitter.com), [Flipkart](https://twitter.com/naqvitalha/status/969577892991549440), [Uber](https://www.youtube.com/watch?v=RV9rxrNIxnY), and [Major League Soccer](https://matchcenter.mlssoccer.com). Software engineers from Meta, Twitter, and Expo continue to contribute design and patches to the project. Developing a Web compatibility layer for React Native involves balancing the needs of high-quality Web apps with the value of React Native API compatibility. There are instances where parts of the React Native API are co-opted to infer information that is necessary or beneficial to products running in Web browsers. Other times there are use cases that are not accomodated by the APIs provided; even when that information cannot be pragmatically incorporated into the existing React Native API design constraints, it still helps to inform which API changes are needed over the long term. diff --git a/packages/docs/src/pages/docs/appendix/unstable-apis.md b/packages/docs/src/pages/docs/appendix/unstable-apis.md index 9fc29c4b81..f8cc6d1a68 100644 --- a/packages/docs/src/pages/docs/appendix/unstable-apis.md +++ b/packages/docs/src/pages/docs/appendix/unstable-apis.md @@ -2,11 +2,12 @@ title: Unstable APIs date: Last Modified permalink: /docs/unstable-apis/index.html -description: +description: eleventyNavigation: key: Unstable APIs parent: Appendix order: 1 + label: "Change" --- :::lead @@ -28,13 +29,16 @@ This also works with composite components defined in your existing component gal ```js import RaisedButton from 'material-ui/RaisedButton'; -import { unstable_createElement } from 'react-native-web'; -import { StyleSheet } from 'react-native'; +import { unstable_createElement, useLocaleContext } from 'react-native-web'; +import { StyleSheet, } from 'react-native'; -const CustomButton = (props) => unstable_createElement(RaisedButton, { - ...props, - style: [ styles.button, props.style ] -}); +const CustomButton = (props) => { + const { direction } = useLocaleContext(); + return unstable_createElement(RaisedButton, { + ...props, + style: [ styles.button, props.style ] + }); +}, { writingDirection: direction }); const styles = StyleSheet.create({ button: { @@ -43,14 +47,6 @@ const styles = StyleSheet.create({ }); ``` -And `unstable_createElement` can be used as drop-in replacement for `React.createElement`: - -```jsx -/* @jsx unstable_createElement */ -import { unstable_createElement } from 'react-native-web'; -const Video = (props) =>