diff --git a/packages/babel-plugin-react-native-web/src/__tests__/__snapshots__/index-test.js.snap b/packages/babel-plugin-react-native-web/src/__tests__/__snapshots__/index-test.js.snap index 62166c18..3a81278d 100644 --- a/packages/babel-plugin-react-native-web/src/__tests__/__snapshots__/index-test.js.snap +++ b/packages/babel-plugin-react-native-web/src/__tests__/__snapshots__/index-test.js.snap @@ -1,74 +1,57 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Rewrite react-native to react-native-web export from "react-native": export from "react-native" 1`] = ` +exports[`[commonjs] Rewrite react-native to react-native-web export from "react-native": export from "react-native" 1`] = ` export { View } from 'react-native'; export { StyleSheet, Text, unstable_createElement } from 'react-native'; ↓ ↓ ↓ ↓ ↓ ↓ -export { default as View } from 'react-native-web/dist/exports/View'; -export { default as StyleSheet } from 'react-native-web/dist/exports/StyleSheet'; -export { default as Text } from 'react-native-web/dist/exports/Text'; -export { default as unstable_createElement } from 'react-native-web/dist/exports/createElement'; +export { default as View } from 'react-native-web/dist/cjs/exports/View'; +export { default as StyleSheet } from 'react-native-web/dist/cjs/exports/StyleSheet'; +export { default as Text } from 'react-native-web/dist/cjs/exports/Text'; +export { default as unstable_createElement } from 'react-native-web/dist/cjs/exports/createElement'; `; -exports[`Rewrite react-native to react-native-web export from "react-native-web": export from "react-native-web" 1`] = ` +exports[`[commonjs] Rewrite react-native to react-native-web export from "react-native-web": export from "react-native-web" 1`] = ` export { View } from 'react-native-web'; export { StyleSheet, Text, unstable_createElement } from 'react-native-web'; ↓ ↓ ↓ ↓ ↓ ↓ -export { default as View } from 'react-native-web/dist/exports/View'; -export { default as StyleSheet } from 'react-native-web/dist/exports/StyleSheet'; -export { default as Text } from 'react-native-web/dist/exports/Text'; -export { default as unstable_createElement } from 'react-native-web/dist/exports/createElement'; +export { default as View } from 'react-native-web/dist/cjs/exports/View'; +export { default as StyleSheet } from 'react-native-web/dist/cjs/exports/StyleSheet'; +export { default as Text } from 'react-native-web/dist/cjs/exports/Text'; +export { default as unstable_createElement } from 'react-native-web/dist/cjs/exports/createElement'; `; -exports[`Rewrite react-native to react-native-web import from "react-native": import from "react-native" 1`] = ` +exports[`[commonjs] Rewrite react-native to react-native-web import from "react-native": import from "react-native" 1`] = ` import ReactNative from 'react-native'; -import { View } from 'react-native'; +import { StyleSheet, View } from 'react-native'; import { Invalid, View as MyView } from 'react-native'; import { useLocaleContext } from 'react-native'; import * as ReactNativeModules from 'react-native'; ↓ ↓ ↓ ↓ ↓ ↓ -import ReactNative from 'react-native-web/dist/index'; -import View from 'react-native-web/dist/exports/View'; -import { Invalid } from 'react-native-web/dist/index'; -import MyView from 'react-native-web/dist/exports/View'; -import useLocaleContext from 'react-native-web/dist/exports/useLocaleContext'; -import * as ReactNativeModules from 'react-native-web/dist/index'; - - -`; - -exports[`Rewrite react-native to react-native-web import from "react-native": import from "react-native" 2`] = ` - -import ReactNative from 'react-native'; -import { View } from 'react-native'; -import { Invalid, View as MyView } from 'react-native'; -import * as ReactNativeModules from 'react-native'; - - ↓ ↓ ↓ ↓ ↓ ↓ - import ReactNative from 'react-native-web/dist/cjs/index'; +import StyleSheet from 'react-native-web/dist/cjs/exports/StyleSheet'; import View from 'react-native-web/dist/cjs/exports/View'; import { Invalid } from 'react-native-web/dist/cjs/index'; import MyView from 'react-native-web/dist/cjs/exports/View'; +import useLocaleContext from 'react-native-web/dist/cjs/exports/useLocaleContext'; import * as ReactNativeModules from 'react-native-web/dist/cjs/index'; `; -exports[`Rewrite react-native to react-native-web import from "react-native-web": import from "react-native-web" 1`] = ` +exports[`[commonjs] Rewrite react-native to react-native-web import from "react-native-web": import from "react-native-web" 1`] = ` import { unstable_createElement } from 'react-native-web'; import { StyleSheet, View, Pressable, processColor } from 'react-native-web'; @@ -76,33 +59,17 @@ import * as ReactNativeModules from 'react-native-web'; ↓ ↓ ↓ ↓ ↓ ↓ -import unstable_createElement from 'react-native-web/dist/exports/createElement'; -import StyleSheet from 'react-native-web/dist/exports/StyleSheet'; -import View from 'react-native-web/dist/exports/View'; -import Pressable from 'react-native-web/dist/exports/Pressable'; -import processColor from 'react-native-web/dist/exports/processColor'; -import * as ReactNativeModules from 'react-native-web/dist/index'; +import unstable_createElement from 'react-native-web/dist/cjs/exports/createElement'; +import StyleSheet from 'react-native-web/dist/cjs/exports/StyleSheet'; +import View from 'react-native-web/dist/cjs/exports/View'; +import Pressable from 'react-native-web/dist/cjs/exports/Pressable'; +import processColor from 'react-native-web/dist/cjs/exports/processColor'; +import * as ReactNativeModules from 'react-native-web/dist/cjs/index'; `; -exports[`Rewrite react-native to react-native-web require "react-native": require "react-native" 1`] = ` - -const ReactNative = require('react-native'); -const { View } = require('react-native'); -const { StyleSheet, Pressable } = require('react-native'); - - ↓ ↓ ↓ ↓ ↓ ↓ - -const ReactNative = require('react-native-web/dist/index'); -const View = require('react-native-web/dist/exports/View').default; -const StyleSheet = require('react-native-web/dist/exports/StyleSheet').default; -const Pressable = require('react-native-web/dist/exports/Pressable').default; - - -`; - -exports[`Rewrite react-native to react-native-web require "react-native": require "react-native" 2`] = ` +exports[`[commonjs] Rewrite react-native to react-native-web require "react-native": require "react-native" 1`] = ` const ReactNative = require('react-native'); const { View } = require('react-native'); @@ -120,7 +87,114 @@ const Pressable = `; -exports[`Rewrite react-native to react-native-web require "react-native-web": require "react-native-web" 1`] = ` +exports[`[commonjs] Rewrite react-native to react-native-web require "react-native-web": require "react-native-web" 1`] = ` + +const ReactNative = require('react-native-web'); +const { unstable_createElement } = require('react-native-web'); +const { StyleSheet, View, Pressable, processColor } = require('react-native-web'); + + ↓ ↓ ↓ ↓ ↓ ↓ + +const ReactNative = require('react-native-web/dist/cjs/index'); +const unstable_createElement = + require('react-native-web/dist/cjs/exports/createElement').default; +const StyleSheet = + require('react-native-web/dist/cjs/exports/StyleSheet').default; +const View = require('react-native-web/dist/cjs/exports/View').default; +const Pressable = + require('react-native-web/dist/cjs/exports/Pressable').default; +const processColor = + require('react-native-web/dist/cjs/exports/processColor').default; + + +`; + +exports[`[legacy] Rewrite react-native to react-native-web export from "react-native": export from "react-native" 1`] = ` + +export { View } from 'react-native'; +export { StyleSheet, Text, unstable_createElement } from 'react-native'; + + ↓ ↓ ↓ ↓ ↓ ↓ + +export { default as View } from 'react-native-web/dist/exports/View'; +export { default as StyleSheet } from 'react-native-web/dist/exports/StyleSheet'; +export { default as Text } from 'react-native-web/dist/exports/Text'; +export { default as unstable_createElement } from 'react-native-web/dist/exports/createElement'; + + +`; + +exports[`[legacy] Rewrite react-native to react-native-web export from "react-native-web": export from "react-native-web" 1`] = ` + +export { View } from 'react-native-web'; +export { StyleSheet, Text, unstable_createElement } from 'react-native-web'; + + ↓ ↓ ↓ ↓ ↓ ↓ + +export { default as View } from 'react-native-web/dist/exports/View'; +export { default as StyleSheet } from 'react-native-web/dist/exports/StyleSheet'; +export { default as Text } from 'react-native-web/dist/exports/Text'; +export { default as unstable_createElement } from 'react-native-web/dist/exports/createElement'; + + +`; + +exports[`[legacy] Rewrite react-native to react-native-web import from "react-native": import from "react-native" 1`] = ` + +import ReactNative from 'react-native'; +import { StyleSheet, View } from 'react-native'; +import { Invalid, View as MyView } from 'react-native'; +import { useLocaleContext } from 'react-native'; +import * as ReactNativeModules from 'react-native'; + + ↓ ↓ ↓ ↓ ↓ ↓ + +import ReactNative from 'react-native-web/dist/index'; +import StyleSheet from 'react-native-web/dist/exports/StyleSheet'; +import View from 'react-native-web/dist/exports/View'; +import { Invalid } from 'react-native-web/dist/index'; +import MyView from 'react-native-web/dist/exports/View'; +import useLocaleContext from 'react-native-web/dist/exports/useLocaleContext'; +import * as ReactNativeModules from 'react-native-web/dist/index'; + + +`; + +exports[`[legacy] Rewrite react-native to react-native-web import from "react-native-web": import from "react-native-web" 1`] = ` + +import { unstable_createElement } from 'react-native-web'; +import { StyleSheet, View, Pressable, processColor } from 'react-native-web'; +import * as ReactNativeModules from 'react-native-web'; + + ↓ ↓ ↓ ↓ ↓ ↓ + +import unstable_createElement from 'react-native-web/dist/exports/createElement'; +import StyleSheet from 'react-native-web/dist/exports/StyleSheet'; +import View from 'react-native-web/dist/exports/View'; +import Pressable from 'react-native-web/dist/exports/Pressable'; +import processColor from 'react-native-web/dist/exports/processColor'; +import * as ReactNativeModules from 'react-native-web/dist/index'; + + +`; + +exports[`[legacy] Rewrite react-native to react-native-web require "react-native": require "react-native" 1`] = ` + +const ReactNative = require('react-native'); +const { View } = require('react-native'); +const { StyleSheet, Pressable } = require('react-native'); + + ↓ ↓ ↓ ↓ ↓ ↓ + +const ReactNative = require('react-native-web/dist/index'); +const View = require('react-native-web/dist/exports/View').default; +const StyleSheet = require('react-native-web/dist/exports/StyleSheet').default; +const Pressable = require('react-native-web/dist/exports/Pressable').default; + + +`; + +exports[`[legacy] Rewrite react-native to react-native-web require "react-native-web": require "react-native-web" 1`] = ` const ReactNative = require('react-native-web'); const { unstable_createElement } = require('react-native-web'); @@ -138,4 +212,101 @@ const processColor = require('react-native-web/dist/exports/processColor').default; +`; + +exports[`Rewrite react-native to react-native-web export from "react-native": export from "react-native" 1`] = ` + +export { View } from 'react-native'; +export { StyleSheet, Text, unstable_createElement } from 'react-native'; + + ↓ ↓ ↓ ↓ ↓ ↓ + +export { View } from 'react-native'; +export { StyleSheet, Text, unstable_createElement } from 'react-native'; + + +`; + +exports[`Rewrite react-native to react-native-web export from "react-native-web": export from "react-native-web" 1`] = ` + +export { View } from 'react-native-web'; +export { StyleSheet, Text, unstable_createElement } from 'react-native-web'; + + ↓ ↓ ↓ ↓ ↓ ↓ + +export { View } from 'react-native-web'; +export { StyleSheet, Text, unstable_createElement } from 'react-native-web'; + + +`; + +exports[`Rewrite react-native to react-native-web import from "react-native": import from "react-native" 1`] = ` + +import ReactNative from 'react-native'; +import { StyleSheet, View } from 'react-native'; +import { Invalid, View as MyView } from 'react-native'; +import { useLocaleContext } from 'react-native'; +import * as ReactNativeModules from 'react-native'; + + ↓ ↓ ↓ ↓ ↓ ↓ + +import ReactNative from 'react-native'; +import StyleSheet from 'react-native-web/dist/exports/StyleSheet/runtime'; +import { View } from 'react-native'; +import { Invalid, View as MyView } from 'react-native'; +import { useLocaleContext } from 'react-native'; +import * as ReactNativeModules from 'react-native'; + + +`; + +exports[`Rewrite react-native to react-native-web import from "react-native-web": import from "react-native-web" 1`] = ` + +import { unstable_createElement } from 'react-native-web'; +import { StyleSheet, View, Pressable, processColor } from 'react-native-web'; +import * as ReactNativeModules from 'react-native-web'; + + ↓ ↓ ↓ ↓ ↓ ↓ + +import { unstable_createElement } from 'react-native-web'; +import StyleSheet from 'react-native-web/dist/exports/StyleSheet/runtime'; +import { View, Pressable, processColor } from 'react-native'; +import * as ReactNativeModules from 'react-native-web'; + + +`; + +exports[`Rewrite react-native to react-native-web require "react-native": require "react-native" 1`] = ` + +const ReactNative = require('react-native'); +const { View } = require('react-native'); +const { StyleSheet, Pressable } = require('react-native'); + + ↓ ↓ ↓ ↓ ↓ ↓ + +const ReactNative = require('react-native'); +const { View } = require('react-native'); +const { StyleSheet, Pressable } = require('react-native'); + + +`; + +exports[`Rewrite react-native to react-native-web require "react-native-web": require "react-native-web" 1`] = ` + +const ReactNative = require('react-native-web'); +const { unstable_createElement } = require('react-native-web'); +const { StyleSheet, View, Pressable, processColor } = require('react-native-web'); + + ↓ ↓ ↓ ↓ ↓ ↓ + +const ReactNative = require('react-native-web'); +const { unstable_createElement } = require('react-native-web'); +const { + StyleSheet, + View, + Pressable, + processColor +} = require('react-native-web'); + + `; diff --git a/packages/babel-plugin-react-native-web/src/__tests__/index-test.js b/packages/babel-plugin-react-native-web/src/__tests__/index-test.js index 9ef03779..0f0368c6 100644 --- a/packages/babel-plugin-react-native-web/src/__tests__/index-test.js +++ b/packages/babel-plugin-react-native-web/src/__tests__/index-test.js @@ -1,69 +1,86 @@ const plugin = require('..'); const pluginTester = require('babel-plugin-tester').default; -const tests = [ - // import react-native - { - title: 'import from "react-native"', - code: `import ReactNative from 'react-native'; -import { View } from 'react-native'; +function createTests(pluginOptions) { + return [ + // import react-native + { + title: 'import from "react-native"', + code: `import ReactNative from 'react-native'; +import { StyleSheet, View } from 'react-native'; import { Invalid, View as MyView } from 'react-native'; import { useLocaleContext } from 'react-native'; import * as ReactNativeModules from 'react-native';`, - snapshot: true - }, - { - title: 'import from "react-native"', - code: `import ReactNative from 'react-native'; -import { View } from 'react-native'; -import { Invalid, View as MyView } from 'react-native'; -import * as ReactNativeModules from 'react-native';`, - snapshot: true, - pluginOptions: { commonjs: true } - }, - { - title: 'import from "react-native-web"', - code: `import { unstable_createElement } from 'react-native-web'; + snapshot: true, + pluginOptions + }, + { + title: 'import from "react-native-web"', + code: `import { unstable_createElement } from 'react-native-web'; import { StyleSheet, View, Pressable, processColor } from 'react-native-web'; import * as ReactNativeModules from 'react-native-web';`, - snapshot: true - }, - { - title: 'export from "react-native"', - code: `export { View } from 'react-native'; + snapshot: true, + pluginOptions + }, + { + title: 'export from "react-native"', + code: `export { View } from 'react-native'; export { StyleSheet, Text, unstable_createElement } from 'react-native';`, - snapshot: true - }, - { - title: 'export from "react-native-web"', - code: `export { View } from 'react-native-web'; + snapshot: true, + pluginOptions + }, + { + title: 'export from "react-native-web"', + code: `export { View } from 'react-native-web'; export { StyleSheet, Text, unstable_createElement } from 'react-native-web';`, - snapshot: true - }, - // require react-native - { - title: 'require "react-native"', - code: `const ReactNative = require('react-native'); + snapshot: true, + pluginOptions + }, + // require react-native + { + title: 'require "react-native"', + code: `const ReactNative = require('react-native'); const { View } = require('react-native'); const { StyleSheet, Pressable } = require('react-native');`, - snapshot: true - }, - { - title: 'require "react-native"', - code: `const ReactNative = require('react-native'); -const { View } = require('react-native'); -const { StyleSheet, Pressable } = require('react-native');`, - snapshot: true, - pluginOptions: { commonjs: true } - }, - { - title: 'require "react-native-web"', - code: `const ReactNative = require('react-native-web'); + snapshot: true, + pluginOptions + }, + { + title: 'require "react-native-web"', + code: `const ReactNative = require('react-native-web'); const { unstable_createElement } = require('react-native-web'); const { StyleSheet, View, Pressable, processColor } = require('react-native-web');`, - snapshot: true - } -]; + snapshot: true, + pluginOptions + } + ]; +} + +pluginTester({ + babelOptions: { + generatorOpts: { + jsescOption: { + quotes: 'single' + } + } + }, + plugin, + pluginName: '[legacy] Rewrite react-native to react-native-web', + tests: createTests({}) +}); + +pluginTester({ + babelOptions: { + generatorOpts: { + jsescOption: { + quotes: 'single' + } + } + }, + plugin, + pluginName: '[commonjs] Rewrite react-native to react-native-web', + tests: createTests({ commonjs: true }) +}); pluginTester({ babelOptions: { @@ -75,5 +92,5 @@ pluginTester({ }, plugin, pluginName: 'Rewrite react-native to react-native-web', - tests + tests: createTests({ legacy: false }) }); diff --git a/packages/babel-plugin-react-native-web/src/index.js b/packages/babel-plugin-react-native-web/src/index.js index 17230a85..dcb65332 100644 --- a/packages/babel-plugin-react-native-web/src/index.js +++ b/packages/babel-plugin-react-native-web/src/index.js @@ -42,36 +42,64 @@ module.exports = function ({ types: t }) { ImportDeclaration(path, state) { const { specifiers } = path.node; if (isReactNativeModule(path.node)) { - const imports = specifiers - .map((specifier) => { - if (t.isImportSpecifier(specifier)) { - const importName = specifier.imported.name; - const distLocation = getDistLocation(importName, state.opts); + if (state.opts.legacy !== false) { + const imports = specifiers + .map((specifier) => { + if (t.isImportSpecifier(specifier)) { + const importName = specifier.imported.name; + const distLocation = getDistLocation(importName, state.opts); - if (distLocation) { - return t.importDeclaration( - [ - t.importDefaultSpecifier( - t.identifier(specifier.local.name) - ) - ], - t.stringLiteral(distLocation) - ); + if (distLocation) { + return t.importDeclaration( + [ + t.importDefaultSpecifier( + t.identifier(specifier.local.name) + ) + ], + t.stringLiteral(distLocation) + ); + } } - } - return t.importDeclaration( - [specifier], - t.stringLiteral(getDistLocation('index', state.opts)) - ); - }) - .filter(Boolean); + return t.importDeclaration( + [specifier], + t.stringLiteral(getDistLocation('index', state.opts)) + ); + }) + .filter(Boolean); - path.replaceWithMultiple(imports); + path.replaceWithMultiple(imports); + } else { + const styleSheetSpecifierIndex = specifiers.findIndex( + (specifier) => + specifier.imported && specifier.imported.name === 'StyleSheet' + ); + if (styleSheetSpecifierIndex !== -1) { + const otherSpecifiers = [ + ...specifiers.slice(0, styleSheetSpecifierIndex), + ...specifiers.slice(styleSheetSpecifierIndex + 1) + ]; + + const newImports = [ + t.importDeclaration( + [t.importDefaultSpecifier(t.identifier('StyleSheet'))], + t.stringLiteral( + 'react-native-web/dist/exports/StyleSheet/runtime' + ) + ), + t.importDeclaration( + otherSpecifiers, + t.stringLiteral('react-native') + ) + ]; + + path.replaceWithMultiple(newImports); + } + } } }, ExportNamedDeclaration(path, state) { const { specifiers } = path.node; - if (isReactNativeModule(path.node)) { + if (isReactNativeModule(path.node) && state.opts.legacy !== false) { const exports = specifiers .map((specifier) => { if (t.isExportSpecifier(specifier)) { @@ -104,7 +132,7 @@ module.exports = function ({ types: t }) { } }, VariableDeclaration(path, state) { - if (isReactNativeRequire(t, path.node)) { + if (isReactNativeRequire(t, path.node) && state.opts.legacy !== false) { const { id } = path.node.declarations[0]; if (t.isObjectPattern(id)) { const imports = id.properties diff --git a/packages/react-native-web/src/exports/StyleSheet/runtime.js b/packages/react-native-web/src/exports/StyleSheet/runtime.js new file mode 100644 index 00000000..24514ed6 --- /dev/null +++ b/packages/react-native-web/src/exports/StyleSheet/runtime.js @@ -0,0 +1,32 @@ +/** + * Copyright (c) Nicolas Gallagher. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + */ + +import { localizeStyle } from 'styleq/transform-localize-style'; +import { styleq } from 'styleq'; + +type StyleProps = [string, { [key: string]: mixed } | null]; +type Options = { writingDirection: 'ltr' | 'rtl' }; + +function customStyleq(styles, isRTL) { + return styleq.factory({ + transform(style) { + return localizeStyle(style, isRTL); + } + })(styles); +} + +export default function StyleSheet( + styles: $ReadOnlyArray, + options?: Options +): StyleProps { + const isRTL = options != null && options.writingDirection === 'rtl'; + const styleProps: StyleProps = customStyleq(styles, isRTL); + // inline styles are not processed in any way + return styleProps; +} diff --git a/packages/react-native-web/src/vendor/react-native/Animated/nodes/AnimatedStyle.js b/packages/react-native-web/src/vendor/react-native/Animated/nodes/AnimatedStyle.js index 1b654319..375f960c 100644 --- a/packages/react-native-web/src/vendor/react-native/Animated/nodes/AnimatedStyle.js +++ b/packages/react-native-web/src/vendor/react-native/Animated/nodes/AnimatedStyle.js @@ -15,9 +15,18 @@ import AnimatedTransform from './AnimatedTransform'; import AnimatedWithChildren from './AnimatedWithChildren'; import NativeAnimatedHelper from '../NativeAnimatedHelper'; -import StyleSheet from '../../../../exports/StyleSheet'; - -const flattenStyle = StyleSheet.flatten; +function flattenStyle(...styles: any): { [key: string]: any } { + const flatArray = styles.flat(Infinity); + const result = {}; + for (let i = 0; i < flatArray.length; i++) { + const style = flatArray[i]; + if (style != null && typeof style === 'object') { + // $FlowFixMe + Object.assign(result, style); + } + } + return result; +} function createAnimatedStyle(inputStyle: any): Object { const style = flattenStyle(inputStyle);