diff --git a/.npmignore b/.npmignore
index ff5562e6..507302d6 100644
--- a/.npmignore
+++ b/.npmignore
@@ -4,8 +4,9 @@ node_modules
# Ignore test files
*_tests_
-# Ignore the example app
+# Ignore the example apps
examples/RestaurantsApp/
+examples/create-react-native-app/
# Ignore local/config files
.editorconfig
diff --git a/components/Button.js b/components/Button.js
index fc620c90..7f32e9be 100644
--- a/components/Button.js
+++ b/components/Button.js
@@ -1,12 +1,10 @@
-import React, { Component } from 'react';
-import {
- TouchableOpacity,
-} from 'react-native';
+import React, { PureComponent } from 'react';
+import { TouchableOpacity } from 'react-native';
import { connectStyle } from '@shoutem/theme';
import { connectAnimation } from '@shoutem/animation';
-class Button extends Component {
+class Button extends PureComponent {
render() {
// The underlayColor is not a valid RN style
// property, so we have to unset it here.
diff --git a/components/DropDownMenu/DropDownMenu.js b/components/DropDownMenu/DropDownMenu.js
index 52635fdf..1a2f22cc 100644
--- a/components/DropDownMenu/DropDownMenu.js
+++ b/components/DropDownMenu/DropDownMenu.js
@@ -1,21 +1,18 @@
-import React, {
- Component,
-} from 'react';
+import React, { PureComponent } from 'react';
import _ from 'lodash';
+
import { connectStyle } from '@shoutem/theme';
-import {
- Button,
- Icon,
- Text,
- View,
-} from '../../index';
+import { Button } from '../Button';
+import { Icon } from '../Icon';
+import { Text } from '../Text';
+import { View } from '../View';
import { DropDownModal } from './DropDownModal';
const modalSpecificProps = ['visible', 'onClose'];
const dropDownMenuPropTypes = { ..._.omit(DropDownModal.propTypes, modalSpecificProps) };
-class DropDownMenu extends Component {
+class DropDownMenu extends PureComponent {
/**
* @see DropDownModal.propTypes
*/
diff --git a/components/DropDownMenu/DropDownModal.js b/components/DropDownMenu/DropDownModal.js
index 4b6b42f1..fc3fab48 100644
--- a/components/DropDownMenu/DropDownModal.js
+++ b/components/DropDownMenu/DropDownModal.js
@@ -1,7 +1,5 @@
import PropTypes from 'prop-types';
-import React, {
- Component,
-} from 'react';
+import React, { PureComponent } from 'react';
import {
Modal,
ListView,
@@ -11,6 +9,9 @@ import {
} from 'react-native';
import _ from 'lodash';
+import { connectStyle, changeColorAlpha } from '@shoutem/theme';
+import { TimingDriver, FadeIn, ZoomOut } from '@shoutem/animation';
+
import { Button } from '../Button';
import { Icon } from '../Icon';
import { Text } from '../Text';
@@ -18,17 +19,9 @@ import { View } from '../View';
import { LinearGradient } from '../LinearGradient';
import { TouchableOpacity } from '../TouchableOpacity';
-import { connectStyle, changeColorAlpha } from '@shoutem/theme';
-
-import {
- TimingDriver,
- FadeIn,
- ZoomOut,
-} from '@shoutem/animation';
-
const window = Dimensions.get('window');
-class DropDownModal extends Component {
+class DropDownModal extends PureComponent {
static propTypes = {
/**
* Callback that is called when dropdown option is selected
diff --git a/components/FormGroup.js b/components/FormGroup.js
index 3c654b35..87dbef38 100644
--- a/components/FormGroup.js
+++ b/components/FormGroup.js
@@ -1,11 +1,11 @@
-import React, { Component } from 'react';
+import React, { PureComponent } from 'react';
import { connectStyle } from '@shoutem/theme';
import { connectAnimation } from '@shoutem/animation';
import { View } from './View';
-class FormGroup extends Component {
+class FormGroup extends PureComponent {
render() {
return (
diff --git a/components/GridRow.js b/components/GridRow.js
index c7293fab..2589fefa 100644
--- a/components/GridRow.js
+++ b/components/GridRow.js
@@ -1,15 +1,16 @@
import PropTypes from 'prop-types';
-import React, { Children } from 'react';
+import React, { PureComponent, Children } from 'react';
import {
View as RNView,
ViewPropTypes,
} from 'react-native';
import _ from 'lodash';
-import { View } from './View';
import { connectStyle } from '@shoutem/theme';
import { connectAnimation } from '@shoutem/animation';
+import { View } from './View';
+
/**
* Renders empty placeholder views to fill any empty space
* left by missing views within a row. This is necessary so that
@@ -24,7 +25,7 @@ function renderPlaceholderViews(count) {
// Ref needed
// eslint-disable-next-line react/prefer-stateless-function
-class GridRow extends React.Component {
+class GridRow extends PureComponent {
render() {
const { children, columns } = this.props;
const missingElementsCount = columns - Children.count(children);
diff --git a/components/HorizontalPager/HorizontalPager.js b/components/HorizontalPager/HorizontalPager.js
index ac46901d..214bb985 100644
--- a/components/HorizontalPager/HorizontalPager.js
+++ b/components/HorizontalPager/HorizontalPager.js
@@ -1,20 +1,16 @@
import PropTypes from 'prop-types';
-import React, { Component } from 'react';
+import React, { PureComponent } from 'react';
import {
ScrollView,
InteractionManager,
LayoutAnimation,
} from 'react-native';
-
import _ from 'lodash';
import { connectStyle } from '@shoutem/theme';
-import {
- View,
-} from '../../index';
-
+import { View } from '../View';
import { Page } from './Page';
/**
@@ -28,7 +24,7 @@ import { Page } from './Page';
* ScrollView and ViewPagerAndroid for this matter.
*
*/
-class HorizontalPager extends Component {
+class HorizontalPager extends PureComponent {
static propTypes = {
// Prop defining whether the Pager will bounce back
// when user tries to swipe beyond end of content (iOS only)
diff --git a/components/HorizontalPager/Page.js b/components/HorizontalPager/Page.js
index 75414940..1643f4ae 100644
--- a/components/HorizontalPager/Page.js
+++ b/components/HorizontalPager/Page.js
@@ -1,7 +1,7 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
-import { View } from '../../index';
+import { View } from '../View';
/**
* A HorizontalPager page. This component is used in
diff --git a/components/ImageGallery/ImageGalleryBase.js b/components/ImageGallery/ImageGalleryBase.js
index 582a18b1..5b596f5f 100644
--- a/components/ImageGallery/ImageGalleryBase.js
+++ b/components/ImageGallery/ImageGalleryBase.js
@@ -1,20 +1,16 @@
import PropTypes from 'prop-types';
-import React, { Component } from 'react';
-
+import React, { PureComponent } from 'react';
import _ from 'lodash';
-import {
- View,
- HorizontalPager,
- LoadingIndicator,
- Image,
-} from '../../index';
-
+import { View } from '../View';
+import { HorizontalPager } from '../HorizontalPager';
+import { LoadingIndicator } from '../LoadingIndicator';
+import { Image } from '../Image';
const IMAGE_PREVIEW_MODE = 'imagePreview';
const IMAGE_GALLERY_MODE = 'gallery';
-export class ImageGalleryBase extends Component {
+export class ImageGalleryBase extends PureComponent {
/**
* The image preview mode is the mode in which
* the user can zoom in/out and pan the image around.
diff --git a/components/ImageGalleryOverlay.js b/components/ImageGalleryOverlay.js
index fde23726..08a57dd5 100644
--- a/components/ImageGalleryOverlay.js
+++ b/components/ImageGalleryOverlay.js
@@ -1,19 +1,14 @@
import PropTypes from 'prop-types';
-import React, { Component } from 'react';
-import {
- ScrollView,
-} from 'react-native';
+import React, { PureComponent } from 'react';
+import { ScrollView } from 'react-native';
import { connectStyle } from '@shoutem/theme';
import { connectAnimation } from '@shoutem/animation';
-import {
- View,
- Subtitle,
- Caption,
- Icon,
- TouchableOpacity,
-} from './../index';
+import { Caption, Subtitle } from './Text';
+import { Icon } from './Icon';
+import { View } from './View';
+import { TouchableOpacity } from './TouchableOpacity';
const DESCRIPTION_LENGTH_TRIM_LIMIT = 90;
@@ -22,7 +17,7 @@ const DESCRIPTION_LENGTH_TRIM_LIMIT = 90;
* images in a gallery. It can display a title and
* a description of an image.
*/
-class ImageGalleryOverlay extends Component {
+class ImageGalleryOverlay extends PureComponent {
static propTypes = {
title: PropTypes.string,
description: PropTypes.string,
diff --git a/components/ImagePreview.js b/components/ImagePreview.js
index 2b28037f..aba01efb 100644
--- a/components/ImagePreview.js
+++ b/components/ImagePreview.js
@@ -1,5 +1,5 @@
import PropTypes from 'prop-types';
-import React, { Component } from 'react';
+import React, { PureComponent } from 'react';
import {
View,
Modal,
@@ -29,7 +29,7 @@ const CLOSE_ICON_SIZE = 25;
* Renders an ImagePreview which shows an inline image preview.
* When clicked, the image is displayed in full screen.
*/
-class ImagePreview extends Component {
+class ImagePreview extends PureComponent {
constructor(props) {
super(props);
this.onPressCloseButton = this.onPressCloseButton.bind(this);
diff --git a/components/InlineGallery.js b/components/InlineGallery.js
index af4d4aef..37e1e694 100644
--- a/components/InlineGallery.js
+++ b/components/InlineGallery.js
@@ -1,5 +1,5 @@
import PropTypes from 'prop-types';
-import React, { Component } from 'react';
+import React, { PureComponent } from 'react';
import _ from 'lodash';
import { connectStyle } from '@shoutem/theme';
@@ -10,7 +10,7 @@ import { Image } from './Image';
import { HorizontalPager } from './HorizontalPager/HorizontalPager';
import { LoadingIndicator } from './LoadingIndicator';
-class InlineGallery extends Component {
+class InlineGallery extends PureComponent {
static propTypes = {
// Array containing objects with image data (shape defined below)
data: PropTypes.arrayOf(
diff --git a/components/LinearGradient.js b/components/LinearGradient.js
index 587208af..551a7ac6 100644
--- a/components/LinearGradient.js
+++ b/components/LinearGradient.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import React, { PureComponent } from 'react';
import RNLinearGradient from 'react-native-linear-gradient';
import _ from 'lodash';
import { connectAnimation } from '@shoutem/animation';
@@ -6,7 +6,7 @@ import { connectStyle } from '@shoutem/theme';
const RNLinearGradientPropsKeys = Object.keys(RNLinearGradient.propTypes);
-class LinearGradient extends React.Component {
+class LinearGradient extends PureComponent {
render () {
const { props } = this;
diff --git a/components/ListView.js b/components/ListView.js
index 1ea88b6e..98166538 100644
--- a/components/ListView.js
+++ b/components/ListView.js
@@ -1,5 +1,5 @@
import PropTypes from 'prop-types';
-import React from 'react';
+import React, { Component } from 'react';
import {
View,
ListView as RNListView,
@@ -8,9 +8,11 @@ import {
Platform,
ScrollView,
} from 'react-native';
+import _ from 'lodash';
+
import { connectStyle } from '@shoutem/theme';
+
import { Spinner } from './Spinner';
-import _ from 'lodash';
const scrollViewProps = _.keys(ScrollView.propTypes);
@@ -64,7 +66,7 @@ class ListDataSource {
}
}
-class ListView extends React.Component {
+class ListView extends Component {
static propTypes = {
autoHideHeader: PropTypes.bool,
style: PropTypes.object,
diff --git a/components/LoadingIndicator.js b/components/LoadingIndicator.js
index bd21824b..db391eda 100644
--- a/components/LoadingIndicator.js
+++ b/components/LoadingIndicator.js
@@ -1,6 +1,4 @@
-import React, {
- Component,
-} from 'react';
+import React, { PureComponent } from 'react';
import { connectStyle } from '@shoutem/theme';
@@ -10,7 +8,7 @@ import { Spinner } from './Spinner';
/**
* Renders a loading indicator (spinner) that fits into available space (container)
*/
-class LoadingIndicator extends Component {
+class LoadingIndicator extends PureComponent {
render() {
return (
diff --git a/components/NavigationBar/NavigationBar.js b/components/NavigationBar/NavigationBar.js
index 1d7f2ba7..eca7ca7a 100644
--- a/components/NavigationBar/NavigationBar.js
+++ b/components/NavigationBar/NavigationBar.js
@@ -1,5 +1,5 @@
import PropTypes from 'prop-types';
-import React, { Component } from 'react';
+import React, { PureComponent } from 'react';
import {
StatusBar,
Animated,
@@ -14,6 +14,7 @@ import color from 'tinycolor2';
import { connectStyle } from '@shoutem/theme';
import { connectAnimation } from '@shoutem/animation';
+import { Device } from '../../helpers';
import composeChildren from './composeChildren';
function getBackgroundColor(style) {
@@ -24,41 +25,8 @@ function getBackgroundColor(style) {
return styleWithBg && styleWithBg.backgroundColor || 'transparent';
}
-function setStatusBarStyle(backgroundColor) {
- function chooseBarStyle(bgColor) {
- return color(bgColor).isDark() ? 'light-content' : 'default';
- }
-
- function setStyle(bgColor) {
- const { statusBarColor } = this.props;
-
- const color = statusBarColor || bgColor;
-
- if (Platform.OS === 'android') {
- StatusBar.setBackgroundColor('rgba(0, 0, 0, 0.2)');
- } else {
- const barStyle = chooseBarStyle(color);
- StatusBar.setBarStyle(barStyle);
- }
- }
-
- // This is little bit hacky, but is the only way
- // to determine the current value of interpolated Animated.Value
- // Other way would be to ask developer to provide Animated.Value
- // used to interpolate backgroundColor. But this way developer doesn't
- // have to concern about status bar if he animates navigation bar color
- if (backgroundColor && backgroundColor._parent instanceof Animated.Value) {
- backgroundColor._parent.addListener((animation) => {
- setStyle(backgroundColor._interpolation(animation.value));
- });
- setStyle(backgroundColor._interpolation(0));
- } else {
- setStyle(backgroundColor);
- }
-}
-
// eslint-disable-next-line react/prefer-stateless-function
-class NavigationBar extends Component {
+class NavigationBar extends PureComponent {
static propTypes = {
leftComponent: PropTypes.node,
centerComponent: PropTypes.node,
@@ -72,6 +40,39 @@ class NavigationBar extends Component {
id: 'default',
};
+ setStatusBarStyle(backgroundColor) {
+ function chooseBarStyle(bgColor) {
+ return color(bgColor).isDark() ? 'light-content' : 'default';
+ }
+
+ function setStyle(bgColor) {
+ const statusBarColor = _.get(this.props, 'statusBarColor', bgColor);
+
+ const color = statusBarColor || bgColor;
+
+ if (Platform.OS === 'android') {
+ StatusBar.setBackgroundColor('rgba(0, 0, 0, 0.2)');
+ } else {
+ const barStyle = chooseBarStyle(color);
+ StatusBar.setBarStyle(barStyle);
+ }
+ }
+
+ // This is little bit hacky, but is the only way
+ // to determine the current value of interpolated Animated.Value
+ // Other way would be to ask developer to provide Animated.Value
+ // used to interpolate backgroundColor. But this way developer doesn't
+ // have to concern about status bar if he animates navigation bar color
+ if (backgroundColor && backgroundColor._parent instanceof Animated.Value) {
+ backgroundColor._parent.addListener((animation) => {
+ setStyle(backgroundColor._interpolation(animation.value));
+ });
+ setStyle(backgroundColor._interpolation(0));
+ } else {
+ setStyle(backgroundColor);
+ }
+ }
+
renderStatusBar() {
const { style } = this.props;
@@ -91,7 +92,7 @@ class NavigationBar extends Component {
} = this.props;
const backgroundColor = getBackgroundColor(style);
- setStatusBarStyle(backgroundColor);
+ this.setStatusBarStyle(backgroundColor);
// Key must be set to render new screen NavigationBar
return (
diff --git a/components/NavigationBar/NavigationBarAnimations.js b/components/NavigationBar/NavigationBarAnimations.js
index 6ef3eef6..03145187 100644
--- a/components/NavigationBar/NavigationBarAnimations.js
+++ b/components/NavigationBar/NavigationBarAnimations.js
@@ -1,4 +1,4 @@
-import * as _ from 'lodash';
+import _ from 'lodash';
class ColorAnimation {
constructor(options) {
diff --git a/components/NavigationBar/composeChildren.js b/components/NavigationBar/composeChildren.js
index d68ee98f..8b004fe6 100644
--- a/components/NavigationBar/composeChildren.js
+++ b/components/NavigationBar/composeChildren.js
@@ -1,4 +1,4 @@
-import React, { Component } from 'react';
+import React, { PureComponent } from 'react';
import { Button } from '../Button';
import { Title } from '../Text';
@@ -74,7 +74,7 @@ function skipUndefined(objValue, srcValue) {
}
// eslint-disable-next-line react/prefer-stateless-function
-const composeChildren = NavigationBarComponent => class extends Component {
+const composeChildren = NavigationBarComponent => class extends PureComponent {
render() {
const newProps = {};
_.forEach(this.props, (value, key) => {
diff --git a/components/PageIndicators.js b/components/PageIndicators.js
index d37b9d2e..2bb122de 100644
--- a/components/PageIndicators.js
+++ b/components/PageIndicators.js
@@ -1,13 +1,14 @@
import PropTypes from 'prop-types';
-import React, { Component } from 'react';
+import React, { PureComponent } from 'react';
import { connectStyle } from '@shoutem/theme';
+
import { View } from './View';
/**
* Renders Page indicators (dots)
*/
-class PageIndicators extends Component {
+class PageIndicators extends PureComponent {
static propTypes = {
// ActiveIndex: number defining which page indicator will be rendered as active (selected)
activeIndex: PropTypes.number,
diff --git a/components/RichMedia.js b/components/RichMedia.js
index cb0a09e8..81c979be 100644
--- a/components/RichMedia.js
+++ b/components/RichMedia.js
@@ -1,5 +1,6 @@
import PropTypes from 'prop-types';
import React from 'react';
+
import { Html } from '../html';
export default function RichMedia({ body }) {
diff --git a/components/ScrollView/ScrollDriverProvider.js b/components/ScrollView/ScrollDriverProvider.js
index cb9e4206..7d7e3a78 100644
--- a/components/ScrollView/ScrollDriverProvider.js
+++ b/components/ScrollView/ScrollDriverProvider.js
@@ -1,14 +1,16 @@
import PropTypes from 'prop-types';
-import React, { Component, Children } from 'react';
+import React, { PureComponent, Children } from 'react';
+import _ from 'lodash';
+
import { DriverShape, ScrollDriver } from '@shoutem/animation';
-import * as _ from 'lodash';
+
/**
* Use this component if you want to share animation driver between unreachable siblings.
* Just wrap their parent component with it. We use it to share an instance of ScrollDriver
* between Screen and NavigationBar automatically. ScrollView from @shoutem/ui uses it to
* register its driver.
*/
-export class ScrollDriverProvider extends Component {
+export class ScrollDriverProvider extends PureComponent {
static childContextTypes = {
driverProvider: PropTypes.object,
animationDriver: DriverShape,
diff --git a/components/ScrollView/ScrollView.js b/components/ScrollView/ScrollView.js
index f27e6434..6401630e 100644
--- a/components/ScrollView/ScrollView.js
+++ b/components/ScrollView/ScrollView.js
@@ -1,7 +1,8 @@
import PropTypes from 'prop-types';
-import React, { Component } from 'react';
+import React, { PureComponent } from 'react';
import { Animated } from 'react-native';
import _ from 'lodash';
+
import { connectStyle } from '@shoutem/theme';
import { ScrollDriver, DriverShape } from '@shoutem/animation';
@@ -11,7 +12,7 @@ import { Device } from '../../helpers';
const isTabBarOnScreen = true;
const IPHONE_X_HOME_INDICATOR_PADDING = isTabBarOnScreen ? 0 : 34;
-class ScrollView extends Component {
+class ScrollView extends PureComponent {
static propTypes = {
...Animated.ScrollView.propTypes,
};
diff --git a/components/ShareButton.js b/components/ShareButton.js
index f345f797..ecc464ad 100644
--- a/components/ShareButton.js
+++ b/components/ShareButton.js
@@ -1,7 +1,5 @@
import PropTypes from 'prop-types';
-import React, {
- Component,
-} from 'react';
+import React, { PureComponent } from 'react';
import { Share, Platform } from 'react-native';
@@ -20,7 +18,7 @@ const { string } = PropTypes;
* It should have the style of its underlying button. That's why it's not connected to style
* or animation.
*/
-class ShareButton extends Component {
+class ShareButton extends PureComponent {
static propTypes = {
// Animation name for share icon
animationName: string,
diff --git a/components/Spinner.js b/components/Spinner.js
index 05050c9d..a72e2fb8 100644
--- a/components/Spinner.js
+++ b/components/Spinner.js
@@ -1,12 +1,12 @@
import PropTypes from 'prop-types';
-import React from 'react';
+import React, { PureComponent } from 'react';
import {
ActivityIndicator,
} from 'react-native';
import { connectStyle } from '@shoutem/theme';
-class Spinner extends React.Component {
+class Spinner extends PureComponent {
render() {
const { style } = this.props;
const indicatorStyle = { ...style };
diff --git a/components/Switch.js b/components/Switch.js
index 1dd7d361..73cee1a6 100644
--- a/components/Switch.js
+++ b/components/Switch.js
@@ -1,18 +1,16 @@
import PropTypes from 'prop-types';
-import React, {
- Component,
-} from 'react';
+import React, { PureComponent } from 'react';
import { TouchableWithoutFeedback } from 'react-native';
-import { View } from '@shoutem/ui';
-
import { connectStyle } from '@shoutem/theme';
import { connectAnimation, TimingDriver } from '@shoutem/animation';
+import { View } from './View';
+
const { bool, func, object, shape } = PropTypes;
-class Switch extends Component {
+class Switch extends PureComponent {
static propTypes = {
// True when switch is on, false otherwise
value: bool,
diff --git a/components/Text.js b/components/Text.js
index 47a3dfdb..4a84d1ad 100644
--- a/components/Text.js
+++ b/components/Text.js
@@ -1,10 +1,10 @@
-import React, { Component } from 'react';
+import React, { PureComponent } from 'react';
import { Text as RNText } from 'react-native';
import { connectStyle } from '@shoutem/theme';
import { connectAnimation } from '@shoutem/animation';
-class Text extends Component {
+class Text extends PureComponent {
render() {
return (
diff --git a/components/TextInput.js b/components/TextInput.js
index 6a2cebbe..96238b64 100644
--- a/components/TextInput.js
+++ b/components/TextInput.js
@@ -1,11 +1,11 @@
import PropTypes from 'prop-types';
-import React, { Component } from 'react';
+import React, { PureComponent } from 'react';
import { TextInput as RNTextInput } from 'react-native';
import { connectStyle } from '@shoutem/theme';
import { connectAnimation } from '@shoutem/animation';
-class TextInput extends Component {
+class TextInput extends PureComponent {
render() {
const { props } = this;
const style = {
diff --git a/components/Touchable.js b/components/Touchable.js
index 5e9a8bf8..fa7efe39 100644
--- a/components/Touchable.js
+++ b/components/Touchable.js
@@ -1,14 +1,12 @@
import PropTypes from 'prop-types';
-import React from 'react';
+import React, { PureComponent } from 'react';
import { Platform } from 'react-native';
import { connectStyle } from '@shoutem/theme';
-import {
- TouchableOpacity,
- TouchableNativeFeedback,
- View,
-} from '../index';
+import { View } from './View';
+import { TouchableOpacity } from './TouchableOpacity';
+import { TouchableNativeFeedback } from './TouchableNativeFeedback';
/**
* A universal touchable component with a
@@ -17,7 +15,7 @@ import {
* iOS, and a TouchableNativeFeedback on
* Android.
*/
-class Touchable extends React.Component {
+class Touchable extends PureComponent {
static propTypes = {
...TouchableOpacity.propTypes,
...TouchableNativeFeedback.propTypes,
diff --git a/components/TouchableNativeFeedback.js b/components/TouchableNativeFeedback.js
index 5b75c027..76f8e5f5 100644
--- a/components/TouchableNativeFeedback.js
+++ b/components/TouchableNativeFeedback.js
@@ -1,10 +1,10 @@
import PropTypes from 'prop-types';
-import React from 'react';
+import React, { PureComponent } from 'react';
import { TouchableNativeFeedback as RNTouchableNativeFeedback } from 'react-native';
import { connectStyle } from '@shoutem/theme';
-class TouchableNativeFeedback extends React.Component {
+class TouchableNativeFeedback extends PureComponent {
static propTypes = {
...RNTouchableNativeFeedback.propTypes,
style: PropTypes.shape({
diff --git a/components/TouchableOpacity.js b/components/TouchableOpacity.js
index da5c4b88..d4d56d11 100644
--- a/components/TouchableOpacity.js
+++ b/components/TouchableOpacity.js
@@ -1,9 +1,9 @@
-import React from 'react';
+import React, { PureComponent } from 'react';
import { TouchableOpacity as RNTouchableOpacity } from 'react-native';
import { connectStyle } from '@shoutem/theme';
-class TouchableOpacity extends React.Component {
+class TouchableOpacity extends PureComponent {
render() {
const props = this.props;
diff --git a/components/Video/Video.js b/components/Video/Video.js
index 734537fa..d99e1b37 100644
--- a/components/Video/Video.js
+++ b/components/Video/Video.js
@@ -1,5 +1,5 @@
import PropTypes from 'prop-types';
-import React from 'react';
+import React, { PureComponent } from 'react';
import {
View,
@@ -8,6 +8,7 @@ import {
import { connectStyle } from '@shoutem/theme';
import { connectAnimation } from '@shoutem/animation';
+
import VideoSourceReader from './VideoSourceReader';
function createSourceObject(source, playerParams, poster) {
@@ -40,7 +41,7 @@ function createSourceObject(source, playerParams, poster) {
*
* @returns {*}
*/
-class Video extends React.Component {
+class Video extends PureComponent {
static propTypes = {
width: PropTypes.number,
height: PropTypes.number,
@@ -75,6 +76,7 @@ class Video extends React.Component {
style={{width, height}}
source={createSourceObject(source, playerParams, poster)}
scrollEnabled={false}
+ originWhitelist={['*']}
/>
);
diff --git a/components/View.js b/components/View.js
index 8735a771..76a8a84d 100644
--- a/components/View.js
+++ b/components/View.js
@@ -1,5 +1,5 @@
import PropTypes from 'prop-types';
-import React, { Component } from 'react';
+import React, { PureComponent } from 'react';
import {
View as RNView,
ViewPropTypes,
@@ -8,9 +8,9 @@ import {
import { connectStyle } from '@shoutem/theme';
import { connectAnimation } from '@shoutem/animation';
-import { LinearGradient } from '../components/LinearGradient';
+import { LinearGradient } from './LinearGradient';
-class View extends Component {
+class View extends PureComponent {
render() {
const style = { ...this.props.style };
let gradient = null;
diff --git a/const.js b/const.js
index 8dc8b0c4..92d289e0 100644
--- a/const.js
+++ b/const.js
@@ -1,4 +1,8 @@
export const NAVIGATION_HEADER_HEIGHT = 64;
+
export const IPHONE_X_NOTCH_PADDING = 30;
export const IPHONE_X_HOME_INDICATOR_PADDING = 34;
export const IPHONE_X_LONG_SIDE = 812;
+
+export const IPHONE_XR_NOTCH_PADDING = 34;
+export const IPHONE_XR_LONG_SIDE = 896;
diff --git a/examples/RestaurantsApp/App.js b/examples/RestaurantsApp/App.js
index 374ef80b..f168c102 100644
--- a/examples/RestaurantsApp/App.js
+++ b/examples/RestaurantsApp/App.js
@@ -1,4 +1,4 @@
-import React, { Component } from 'react';
+import React, { PureComponent } from 'react';
import { createStore, applyMiddleware } from 'redux';
import { Provider } from 'react-redux';
import thunk from 'redux-thunk';
@@ -9,7 +9,7 @@ import Restaurants from './screens/Restaurants';
const createStoreWithMiddleware = applyMiddleware(thunk)(createStore);
const store = createStoreWithMiddleware(reducer);
-export default class App extends Component {
+export default class App extends PureComponent {
render() {
return (
diff --git a/examples/RestaurantsApp/redux.js b/examples/RestaurantsApp/redux.js
index dbbd4d8a..d975f599 100644
--- a/examples/RestaurantsApp/redux.js
+++ b/examples/RestaurantsApp/redux.js
@@ -1,8 +1,6 @@
import { combineReducers } from 'redux';
-import NavigationExperimental from 'react-native-navigation-experimental-compat';
-
-const NavigationStateUtils = NavigationExperimental.StateUtils;
+import { StateUtils as NavigationStateUtils } from 'react-native-navigation-experimental-compat';
const NAV_PUSH = 'NAV_PUSH';
const NAV_POP = 'NAV_POP';
diff --git a/examples/RestaurantsApp/screens/RestaurantDetails.js b/examples/RestaurantsApp/screens/RestaurantDetails.js
index 27111cb6..95081d06 100644
--- a/examples/RestaurantsApp/screens/RestaurantDetails.js
+++ b/examples/RestaurantsApp/screens/RestaurantDetails.js
@@ -1,5 +1,6 @@
import PropTypes from 'prop-types';
-import React, { Component } from 'react';
+import React, { PureComponent } from 'react';
+
import {
ScrollView,
Icon,
@@ -14,11 +15,9 @@ import {
Screen,
} from '@shoutem/ui';
-import {
- NavigationBar,
-} from '@shoutem/ui/navigation';
+import { NavigationBar } from 'shoutem.navigation';
-export default class RestaurantDetails extends Component {
+export default class RestaurantDetails extends PureComponent {
static propTypes = {
restaurant: PropTypes.object,
};
diff --git a/examples/RestaurantsApp/screens/Restaurants.js b/examples/RestaurantsApp/screens/Restaurants.js
index 7a21c78e..0bc70447 100644
--- a/examples/RestaurantsApp/screens/Restaurants.js
+++ b/examples/RestaurantsApp/screens/Restaurants.js
@@ -1,17 +1,14 @@
import PropTypes from 'prop-types';
-import React, { Component } from 'react';
+import React, { PureComponent } from 'react';
import { connect } from 'react-redux';
-import {
- CardStack,
- NavigationBar,
-} from '@shoutem/ui/navigation';
+import { CardStack, NavigationBar } from 'shoutem.navigation';
-import { navigatePop } from '../redux';
import RestaurantsList from './RestaurantsList';
import RestaurantDetails from './RestaurantDetails';
+import { navigatePop } from '../redux';
-class Restaurants extends Component {
+class Restaurants extends PureComponent {
static propTypes = {
onNavigateBack: PropTypes.func.isRequired,
navigationState: PropTypes.object,
@@ -29,6 +26,7 @@ class Restaurants extends Component {
const { route } = props.scene;
let Screen = route.key === 'RestaurantDetails' ? RestaurantDetails : RestaurantsList;
+
return ();
}
diff --git a/examples/RestaurantsApp/screens/RestaurantsList.js b/examples/RestaurantsApp/screens/RestaurantsList.js
index 596457b3..7b807d56 100644
--- a/examples/RestaurantsApp/screens/RestaurantsList.js
+++ b/examples/RestaurantsApp/screens/RestaurantsList.js
@@ -1,5 +1,7 @@
import PropTypes from 'prop-types';
-import React, { Component } from 'react';
+import React, { PureComponent } from 'react';
+import { connect } from 'react-redux';
+
import {
ImageBackground,
ListView,
@@ -11,20 +13,18 @@ import {
Divider,
} from '@shoutem/ui';
-import {
- NavigationBar,
-} from '@shoutem/ui/navigation';
-import { connect } from 'react-redux';
+import { NavigationBar } from 'shoutem.navigation';
import { navigatePush } from '../redux';
-class RestaurantsList extends Component {
+class RestaurantsList extends PureComponent {
static propTypes = {
onButtonPress: PropTypes.func,
};
constructor(props) {
super(props);
+
this.renderRow = this.renderRow.bind(this);
}
@@ -55,10 +55,10 @@ class RestaurantsList extends Component {
return (
- this.renderRow(restaurant)}
- />
+ this.renderRow(restaurant)}
+ />
);
}
diff --git a/examples/components/Buttons.js b/examples/components/Buttons.js
index 944cb4a8..734ca12a 100644
--- a/examples/components/Buttons.js
+++ b/examples/components/Buttons.js
@@ -1,12 +1,10 @@
import React from 'react';
+import { Icon } from '../../components/Icon';
+import { Text } from '../../components/Text';
+import { View } from '../../components/View';
+import { Button } from '../../components/Button';
import { Stage } from './Stage';
-import {
- View,
- Button,
- Icon,
- Text,
-} from '../../index';
export function Buttons() {
return (
diff --git a/examples/components/Cards.js b/examples/components/Cards.js
index 4f1ff4e6..fbd13d4e 100644
--- a/examples/components/Cards.js
+++ b/examples/components/Cards.js
@@ -1,15 +1,12 @@
import React from 'react';
+import { Caption, Subtitle } from '../../components/Text';
+import { View } from '../../components/View';
+import { Card } from '../../components/Card';
+import { Image } from '../../components/Image';
+import { Icon } from '../../components/Icon';
+import { Button } from '../../components/Button';
import { Stage } from './Stage';
-import {
- View,
- Card,
- Image,
- Subtitle,
- Caption,
- Icon,
- Button,
-} from '../../index';
export function Cards() {
return (
diff --git a/examples/components/Dividers.js b/examples/components/Dividers.js
index b09d938e..3cb865df 100644
--- a/examples/components/Dividers.js
+++ b/examples/components/Dividers.js
@@ -1,11 +1,9 @@
import React from 'react';
+import { Caption } from '../../components/Text';
import { View } from '../../components/View';
+import { Divider } from '../../components/Divider';
import { Stage } from './Stage';
-import {
- Caption,
- Divider,
-} from '../../index';
export function Dividers() {
return (
diff --git a/examples/components/DropDownMenus.js b/examples/components/DropDownMenus.js
index c3c21546..944f13fb 100644
--- a/examples/components/DropDownMenus.js
+++ b/examples/components/DropDownMenus.js
@@ -1,13 +1,10 @@
-import React, { Component } from 'react';
+import React, { PureComponent } from 'react';
+import { Caption } from '../../components/Text';
import { View } from '../../components/View';
-import { Stage } from './Stage';
+import { FormGroup } from '../../components/FormGroup';
import { DropDownMenu } from '../../components/DropDownMenu';
-
-import {
- Caption,
- FormGroup,
-} from '../../index';
+import { Stage } from './Stage';
const options = [
{
@@ -28,7 +25,7 @@ const options = [
const emptyOption = { id: '', name: 'Select'};
const optionsWithEmptyOption = [emptyOption, ...options];
-export class DropDownMenus extends Component {
+export class DropDownMenus extends PureComponent {
constructor() {
super();
this.state = {
diff --git a/examples/components/Examples.js b/examples/components/Examples.js
index 32295e7e..965b35e7 100644
--- a/examples/components/Examples.js
+++ b/examples/components/Examples.js
@@ -1,6 +1,9 @@
-import React, { Component } from 'react';
+import React, { PureComponent } from 'react';
-import { Screen, DropDownMenu, Divider, ScrollView, } from '../../index';
+import { Screen } from '../../components/Screen';
+import { Divider } from '../../components/Divider';
+import { ScrollView } from '../../components/ScrollView';
+import { DropDownMenu } from '../../components/DropDownMenu';
import { Typography } from './Typography';
import { Dividers } from './Dividers';
@@ -32,7 +35,7 @@ const examples = [
{ title: 'Form Components', component: FormComponents },
];
-export class Examples extends Component {
+export class Examples extends PureComponent {
constructor() {
super();
this.state = {
diff --git a/examples/components/FormComponents.js b/examples/components/FormComponents.js
index 0743aba7..806dafb9 100644
--- a/examples/components/FormComponents.js
+++ b/examples/components/FormComponents.js
@@ -1,17 +1,13 @@
-import React, {
- Component,
-} from 'react';
+import React, { PureComponent } from 'react';
+import { Caption } from '../../components/Text';
+import { View } from '../../components/View';
+import { Switch } from '../../components/Switch';
+import { FormGroup } from '../../components/FormGroup';
+import { TextInput } from '../../components/TextInput';
import { Stage } from './Stage';
-import {
- Caption,
- FormGroup,
- Switch,
- View,
- TextInput,
-} from '../../index';
-export class FormComponents extends Component {
+export class FormComponents extends PureComponent {
constructor() {
super();
this.state = {
diff --git a/examples/components/Headers.js b/examples/components/Headers.js
index 79001f21..735062c4 100644
--- a/examples/components/Headers.js
+++ b/examples/components/Headers.js
@@ -1,18 +1,12 @@
import React from 'react';
+import { Text, Caption, Subtitle, Title, Heading } from '../../components/Text';
+import { Icon } from '../../components/Icon';
+import { View } from '../../components/View';
+import { Tile } from '../../components/Tile';
+import { Button } from '../../components/Button';
+import { Overlay } from '../../components/Overlay';
import { Stage } from './Stage';
-import {
- Heading,
- View,
- Tile,
- Text,
- Title,
- Subtitle,
- Caption,
- Icon,
- Overlay,
- Button,
-} from '../../index';
export function Headers() {
return (
diff --git a/examples/components/HorizontalPagers.js b/examples/components/HorizontalPagers.js
index 960964b3..a473611e 100644
--- a/examples/components/HorizontalPagers.js
+++ b/examples/components/HorizontalPagers.js
@@ -1,15 +1,12 @@
import React from 'react';
import { Dimensions } from 'react-native';
+import { Caption, Subtitle } from '../../Text';
+import { View } from '../../components/View';
+import { HorizontalPager } from '../../components/HorizontalPager';
+import { Tile } from '../../Tile';
+import { ImageBackground } from '../../ImageBackground';
import { Stage } from './Stage';
-import {
- View,
- HorizontalPager,
- Tile,
- ImageBackground,
- Subtitle,
- Caption,
-} from '../../index';
const window = Dimensions.get('window');
diff --git a/examples/components/ImageGalleries.js b/examples/components/ImageGalleries.js
index ed2ae343..a582edc1 100644
--- a/examples/components/ImageGalleries.js
+++ b/examples/components/ImageGalleries.js
@@ -1,11 +1,9 @@
import React from 'react';
import { Dimensions } from 'react-native';
+import { View } from '../../components/View';
+import { ImageGallery } from '../../components/ImageGallery';
import { Stage } from './Stage';
-import {
- View,
- ImageGallery,
-} from '../../index';
const window = Dimensions.get('window');
diff --git a/examples/components/Images.js b/examples/components/Images.js
index 2b2daa20..677e8dfe 100644
--- a/examples/components/Images.js
+++ b/examples/components/Images.js
@@ -1,8 +1,8 @@
import React from 'react';
import { View } from '../../components/View';
-import { Stage } from './Stage';
import { Image } from '../../components/Image';
+import { Stage } from './Stage';
export function Images() {
return (
diff --git a/examples/components/InlineGalleries.js b/examples/components/InlineGalleries.js
index 90dc8dbc..5f38b1a2 100644
--- a/examples/components/InlineGalleries.js
+++ b/examples/components/InlineGalleries.js
@@ -1,11 +1,9 @@
import React from 'react';
import { Dimensions } from 'react-native';
+import { View } from '../../components/View';
+import { InlineGallery } from '../../components/InlineGallery';
import { Stage } from './Stage';
-import {
- View,
- InlineGallery,
-} from '../../index';
const window = Dimensions.get('window');
diff --git a/examples/components/NavigationBars.js b/examples/components/NavigationBars.js
index 66e2fab0..d69579d0 100644
--- a/examples/components/NavigationBars.js
+++ b/examples/components/NavigationBars.js
@@ -1,18 +1,14 @@
import React from 'react';
import { Dimensions } from 'react-native';
+import { Text, Title, Heading } from '../../components/Text';
import { View } from '../../components/View';
+import { Icon } from '../../components/Icon';
+import { Button } from '../../components/Button';
+import { DropDownMenu } from '../../components/DropDownMenu';
+import { NavigationBar } from '../../components/NavigationBar';
+import { ImageBackground } from '../../components/ImageBackground';
import { Stage } from './Stage';
-import {
- Heading,
- NavigationBar,
- Title,
- Text,
- ImageBackground,
- Button,
- Icon,
- DropDownMenu,
-} from '../../index';
const window = Dimensions.get('window');
diff --git a/examples/components/Rows.js b/examples/components/Rows.js
index e541fa0e..7cb247e6 100644
--- a/examples/components/Rows.js
+++ b/examples/components/Rows.js
@@ -1,16 +1,12 @@
import React from 'react';
+import { Text, Caption, Subtitle } from '../../components/Text';
+import { Row } from '../../components/Row';
+import { Icon } from '../../components/Icon';
+import { View } from '../../components/View';
+import { Image } from '../../components/Image';
+import { Button } from '../../components/Button';
import { Stage } from './Stage';
-import {
- View,
- Row,
- Text,
- Subtitle,
- Caption,
- Image,
- Button,
- Icon,
-} from '../../index';
export function Rows() {
return (
diff --git a/examples/components/Spinners.js b/examples/components/Spinners.js
index 73bc7572..7610bbcd 100644
--- a/examples/components/Spinners.js
+++ b/examples/components/Spinners.js
@@ -1,10 +1,8 @@
import React from 'react';
+import { View } from '../../components/View';
+import { Spinner } from '../../components/Spinner';
import { Stage } from './Stage';
-import {
- View,
- Spinner,
-} from '../../index';
export function Spinners() {
return (
diff --git a/examples/components/Tiles.js b/examples/components/Tiles.js
index 2af6de29..7f48685a 100644
--- a/examples/components/Tiles.js
+++ b/examples/components/Tiles.js
@@ -1,20 +1,14 @@
import React from 'react';
+import { Text, Caption, Subtitle, Title, Heading } from '../../components/Text';
+import { Icon } from '../../components/Icon';
+import { Tile } from '../../components/Tile';
+import { View } from '../../components/View';
+import { Image } from '../../components/Image';
+import { Button } from '../../components/Button';
+import { Overlay } from '../../components/Overlay';
+import { ImageBackground } from '../../components/ImageBackground';
import { Stage } from './Stage';
-import {
- Heading,
- View,
- Tile,
- Image,
- ImageBackground,
- Text,
- Title,
- Subtitle,
- Caption,
- Icon,
- Overlay,
- Button,
-} from '../../index';
export function Tiles() {
return (
diff --git a/examples/components/Typography.js b/examples/components/Typography.js
index f371df52..9d34db93 100644
--- a/examples/components/Typography.js
+++ b/examples/components/Typography.js
@@ -1,15 +1,8 @@
import React from 'react';
+import { Text, Caption, Subtitle, Title, Heading } from '../../components/Text';
import { View } from '../../components/View';
import { Stage } from './Stage';
-import {
- Text,
- Heading,
- Title,
- Subtitle,
- Description,
- Caption,
-} from '../../components/Text';
export function Typography() {
return (
diff --git a/examples/components/Videos.js b/examples/components/Videos.js
index 9e090549..1baf2e06 100644
--- a/examples/components/Videos.js
+++ b/examples/components/Videos.js
@@ -1,10 +1,10 @@
import React from 'react';
+import { WebView } from 'react-native';
import { View } from '../../components/View';
-import { Stage } from './Stage';
import { Image } from '../../components/Image';
import { Video } from '../../components/Video'
-import { WebView } from 'react-native';
+import { Stage } from './Stage';
export function Videos() {
return (
diff --git a/examples/create-react-native-app/App.js b/examples/create-react-native-app/App.js
index 1012e6f4..1164987f 100644
--- a/examples/create-react-native-app/App.js
+++ b/examples/create-react-native-app/App.js
@@ -1,9 +1,9 @@
-import React, { Component } from 'react';
+import React, { PureComponent } from 'react';
import { StatusBar } from 'react-native';
import { Font, AppLoading } from 'expo';
import { View, Examples } from '@shoutem/ui';
-export default class App extends React.Component {
+export default class App extends PureComponent {
state = {
fontsAreLoaded: false,
};
diff --git a/helpers/device-selector.js b/helpers/device-selector.js
index 801aeaa4..0c111194 100644
--- a/helpers/device-selector.js
+++ b/helpers/device-selector.js
@@ -1,16 +1,24 @@
import { Platform, Dimensions } from 'react-native';
import _ from 'lodash';
-import { IPHONE_X_LONG_SIDE } from '../const';
+import {
+ IPHONE_X_LONG_SIDE,
+ IPHONE_XR_LONG_SIDE,
+} from '../const';
const { OS, isPad, isTVOS } = Platform;
const { width, height } = Dimensions.get('window');
-const dimensionsMatch = (
+const xDimensionsMatch = (
(height === IPHONE_X_LONG_SIDE) || (width === IPHONE_X_LONG_SIDE)
);
-const isIphoneX = (OS === 'ios' && !isPad && !isTVOS && dimensionsMatch);
+const xrDimensionsMatch = (
+ (height === IPHONE_XR_LONG_SIDE) || (width === IPHONE_XR_LONG_SIDE)
+);
+
+const isIphoneX = (OS === 'ios' && !isPad && !isTVOS && xDimensionsMatch);
+const isIphoneXR = (OS === 'ios' && !isPad && !isTVOS && xrDimensionsMatch);
/**
* Receives settings for different devices
@@ -26,10 +34,15 @@ function select(settings) {
return settings.iPhoneX;
}
+ if (settings.iPhoneXR && isIphoneXR) {
+ return settings.iPhoneXR;
+ }
+
return _.get(settings, 'default');
}
export const Device = {
isIphoneX,
+ isIphoneXR,
select,
}
diff --git a/html/Html.js b/html/Html.js
index 293806d6..3b104020 100644
--- a/html/Html.js
+++ b/html/Html.js
@@ -1,5 +1,5 @@
import PropTypes from 'prop-types';
-import React, { Component } from 'react';
+import React, { PureComponent } from 'react';
import { Platform, InteractionManager } from 'react-native';
import _ from 'lodash';
@@ -19,7 +19,7 @@ const defaultElementSettings = {
display: Display.BLOCK,
};
-class Html extends Component {
+class Html extends PureComponent {
static propTypes = {
body: PropTypes.string.isRequired,
renderElement: PropTypes.func,
diff --git a/html/components/Gallery.js b/html/components/Gallery.js
index 8d777275..1bb6706b 100644
--- a/html/components/Gallery.js
+++ b/html/components/Gallery.js
@@ -1,5 +1,5 @@
import PropTypes from 'prop-types';
-import React, { Component } from 'react';
+import React, { PureComponent } from 'react';
import { InlineGallery } from '../../components/InlineGallery';
@@ -7,7 +7,7 @@ import { InlineGallery } from '../../components/InlineGallery';
* Use to render a HTML gallery component.
* Style interface correspond to InlineGallery from @shoutem/ui.
*/
-export default class Gallery extends Component {
+export default class Gallery extends PureComponent {
static propTypes = {
...InlineGallery.propTypes,
handlePhotoPress: PropTypes.func,
diff --git a/html/components/Image.js b/html/components/Image.js
index 3245b6c6..a1c7d8bf 100644
--- a/html/components/Image.js
+++ b/html/components/Image.js
@@ -1,5 +1,5 @@
import PropTypes from 'prop-types';
-import React, { Component } from 'react';
+import React, { PureComponent } from 'react';
import { Image as RNImage } from 'react-native';
import { connectStyle } from '@shoutem/theme';
import _ from 'lodash';
@@ -14,7 +14,7 @@ import { Lightbox } from '../../components/Lightbox';
* Image is not going to be shown before dimensions are determined,
* this component will determine the Image dimensions before rendering an image.
*/
-export default class HtmlImage extends Component {
+export default class HtmlImage extends PureComponent {
static propTypes = {
...RNImage.propTypes,
lightbox: PropTypes.bool,
diff --git a/html/components/SimpleHtml.js b/html/components/SimpleHtml.js
new file mode 100644
index 00000000..abf46287
--- /dev/null
+++ b/html/components/SimpleHtml.js
@@ -0,0 +1,128 @@
+import PropTypes from 'prop-types';
+import { Dimensions, Linking } from 'react-native';
+import React, { PureComponent } from 'react';
+import _ from 'lodash';
+import HTML from 'react-native-render-html';
+
+import {
+ cssStringToObject,
+ cssObjectToString,
+} from 'react-native-render-html/src/HTMLStyles';
+
+import { connectStyle } from '@shoutem/theme';
+import { View } from '../../components/View';
+import { Text } from '../../components/Text';
+
+import getEmptyObjectKeys from '../services/getEmptyObjectKeys';
+
+class SimpleHtml extends PureComponent {
+ static propTypes = {
+ body: PropTypes.string,
+ style: PropTypes.object,
+ customTagStyles: PropTypes.object,
+ customHandleLinkPress: PropTypes.func,
+ };
+
+ constructor(props) {
+ super(props);
+
+ this.onLinkPress = this.onLinkPress.bind(this);
+ this.alterNode = this.alterNode.bind(this);
+ this.renderUnorderedListPrefix = this.renderUnorderedListPrefix.bind(this);
+ this.renderOrderedListPrefix = this.renderOrderedListPrefix.bind(this);
+ }
+
+ onLinkPress(evt, href) {
+ const { customHandleLinkPress } = this.props;
+
+ return customHandleLinkPress ? customHandleLinkPress(href) : Linking.openURL(href);
+ }
+
+ /**
+ * Removes empty (therefore invalid) style attribute properties
+ * Scales down objects with specified width and height if too large
+ */
+ alterNode(node) {
+ const { style } = this.props;
+
+ const styleAttrib = _.get(node, 'attribs.style', '').trim();
+ const nodeWidth = _.get(node, 'attribs.width', false);
+
+ if (!styleAttrib && !nodeWidth) {
+ return false;
+ }
+
+ const paddingValue = style.container.paddingLeft * 2;
+ const maxWidth = Dimensions.get('window').width - paddingValue;
+ const nodeHeight = _.get(node, 'attribus.height');
+ const nodeRatio = nodeWidth/nodeHeight;
+ const resolvedWidth = (nodeWidth > maxWidth) ? maxWidth : nodeWidth;
+ const resolvedHeight = Math.round(resolvedWidth*nodeRatio);
+
+ const nodeStyle = cssStringToObject(styleAttrib);
+ const invalidKeys = getEmptyObjectKeys(nodeStyle);
+
+ if (invalidKeys.length || nodeWidth) {
+ const styleFiltered = _.omit(style, invalidKeys);
+ node.attribs.style = cssObjectToString(styleFiltered);
+ node.attribs.width = resolvedWidth;
+ node.attribs.height = resolvedHeight;
+
+ return node;
+ }
+
+ return false;
+ }
+
+ renderUnorderedListPrefix(htmlAttribs, children, convertedCSSStyles, passProps) {
+ const { style } = this.props;
+
+ return (
+ •
+ );
+ }
+
+ renderOrderedListPrefix(htmlAttribs, children, convertedCSSStyles, passProps) {
+ const { style } = this.props;
+
+ return (
+ {passProps.index + 1}.
+ );
+ }
+
+ render() {
+ const { style, body, customTagStyles } = this.props;
+
+ const paddingValue = style.container.paddingLeft * 2;
+ const maxWidth = Dimensions.get('window').width - paddingValue;
+
+ const tagStyles = {
+ ...style.tags,
+ ...customTagStyles,
+ }
+
+ const listPrefixRenderers = {
+ ul: this.renderUnorderedListPrefix,
+ ol: this.renderOrderedListPrefix,
+ }
+
+ const htmlProps = {
+ html: body,
+ imagesMaxWidth: maxWidth,
+ staticContentMaxWidth: maxWidth,
+ tagsStyles: tagStyles,
+ ignoredStyles: ['font-family', 'letter-spacing', 'transform'],
+ onLinkPress: this.onLinkPress,
+ alterNode: this.alterNode,
+ listsPrefixesRenderers: listPrefixRenderers,
+ };
+
+ return (
+
+
+
+ );
+ }
+}
+
+export default connectStyle('shoutem.ui.SimpleHtml')(SimpleHtml);
diff --git a/html/elements/A.js b/html/elements/A.js
index 7f3db5be..e63c0678 100644
--- a/html/elements/A.js
+++ b/html/elements/A.js
@@ -1,5 +1,5 @@
import PropTypes from 'prop-types';
-import React from 'react';
+import React, { PureComponent } from 'react';
import { Linking } from 'react-native';
import { connectStyle } from '@shoutem/theme';
import _ from 'lodash';
@@ -8,7 +8,7 @@ import { ElementPropTypes, combineMappers, mapElementProps } from '../Html';
import { isImg } from '../elements/Img';
import { Inline } from './Inline';
-class A extends React.Component {
+class A extends PureComponent {
static propTypes = {
...ElementPropTypes,
handleLinkPress: PropTypes.func,
diff --git a/html/elements/Inline.js b/html/elements/Inline.js
index ddd8db27..05fa3e6d 100644
--- a/html/elements/Inline.js
+++ b/html/elements/Inline.js
@@ -1,5 +1,5 @@
import PropTypes from 'prop-types';
-import React from 'react';
+import React, { PureComponent } from 'react';
import _ from 'lodash';
import { View } from '../../components/View';
@@ -129,7 +129,7 @@ function renderGroupedChildren(groupedChildren, renderElement, style) {
* @returns {component}
* @constructor
*/
-export class Inline extends React.Component {
+export class Inline extends PureComponent {
static defaultProps = {
style: {},
};
diff --git a/html/index.js b/html/index.js
index efa43ae6..6f23697a 100644
--- a/html/index.js
+++ b/html/index.js
@@ -14,6 +14,7 @@ import Html, {
renderChildElements,
renderChildren,
} from './Html';
+import SimpleHtml from './components/SimpleHtml';
import Gallery from './components/Gallery';
import Image from './components/Image';
import Inline, { InlineSettings } from './elements/Inline';
@@ -97,4 +98,5 @@ export {
// Components
Gallery,
Image,
+ SimpleHtml,
};
diff --git a/html/services/getEmptyObjectKeys.js b/html/services/getEmptyObjectKeys.js
new file mode 100644
index 00000000..abf0e42f
--- /dev/null
+++ b/html/services/getEmptyObjectKeys.js
@@ -0,0 +1,11 @@
+export default function getEmptyObjectKeys(obj) {
+ return Object.keys(obj).reduce((arr, key) => {
+ const val = String(obj[key]).trim();
+
+ if (!val) {
+ arr.push(key);
+ }
+
+ return arr;
+ }, []);
+}
diff --git a/index.js b/index.js
index eecdaf4d..5e7d73d3 100644
--- a/index.js
+++ b/index.js
@@ -43,6 +43,7 @@ export { LoadingIndicator } from './components/LoadingIndicator';
export { PageIndicators } from './components/PageIndicators';
export { default as RichMedia } from './components/RichMedia';
export { Html } from './html';
+export { SimpleHtml } from './html';
export { ShareButton } from './components/ShareButton';
export { LinearGradient } from './components/LinearGradient';
@@ -70,6 +71,8 @@ export { Device } from './helpers';
export {
IPHONE_X_HOME_INDICATOR_PADDING,
IPHONE_X_NOTCH_PADDING,
+ IPHONE_XR_NOTCH_PADDING,
NAVIGATION_HEADER_HEIGHT,
IPHONE_X_LONG_SIDE,
+ IPHONE_XR_LONG_SIDE,
} from './const';
diff --git a/navigation/NavigationBar.js b/navigation/NavigationBar.js
index 3a48eb1f..ad43e076 100644
--- a/navigation/NavigationBar.js
+++ b/navigation/NavigationBar.js
@@ -49,6 +49,10 @@ class NavigationBar extends Component {
this.setNavBarProps(nextProps);
}
+ componentDidMount() {
+ console.warn("NavigationBar from '@shoutem/ui/navigation' is deprecated and will soon be removed. Use NavigationBar from '@shoutem/ui' instead.");
+ }
+
componentWillUnmount() {
// The parent screen is being unmounted, we can cleanup now
const { getScene, clearNavBarProps } = this.context;
diff --git a/navigation/NavigationBarView.js b/navigation/NavigationBarView.js
index 4cb8a632..0ea16123 100644
--- a/navigation/NavigationBarView.js
+++ b/navigation/NavigationBarView.js
@@ -173,7 +173,7 @@ class NavigationBarView extends PureComponent {
}
setStatusBarStyleIos(statusBarColor, backgroundColor, hasImage) {
- if (isAnimatedStyleValue(backgroundColor) && !Device.isIphoneX) {
+ if (isAnimatedStyleValue(backgroundColor) && !Device.isIphoneX && !Device.isIphoneXR) {
// If the backgroundColor is animated, we want to listen for
// color changes, so that we can update the bar style as the
// animation runs.
diff --git a/navigation/children-composers/navbar-image.composer.js b/navigation/children-composers/navbar-image.composer.js
index 8d6151ba..5d055019 100644
--- a/navigation/children-composers/navbar-image.composer.js
+++ b/navigation/children-composers/navbar-image.composer.js
@@ -2,7 +2,6 @@ import React from 'react';
import _ from 'lodash';
import { NavigationBar } from '../NavigationBar';
import { View, Image, Device } from '../../index';
-import { IPHONE_X_NOTCH_PADDING } from '../../const';
const imageFitContainer = navBarProps => (NavigationBar.fitContainer || navBarProps.fitContainer);
@@ -29,7 +28,7 @@ const createNavBarBackgroundImage = navBarProps => () => {
const navigationBarImage =
(NavigationBar.globalNavigationBarImage || navBarProps.navigationBarImage);
const statusBarColor = _.get(navBarProps, 'style.statusBar.backgroundColor', '#000');
- const statusBarHeight = _.get(navBarProps, 'style.statusBar.height', IPHONE_X_NOTCH_PADDING);
+ const statusBarHeight = _.get(navBarProps, 'style.statusBar.height');
const backgroundImage = (
({
listContent: {
paddingBottom: Device.select({
iPhoneX: IPHONE_X_HOMEBAR_SCROLL_PADDING,
+ iPhoneXR: IPHONE_X_HOMEBAR_SCROLL_PADDING,
default: 0,
})
},
@@ -1422,7 +1425,11 @@ export default (variables = defaultThemeVariables) => ({
statusBar: {
backgroundColor: variables.statusBarColor,
- height: IPHONE_X_NOTCH_PADDING,
+ height: Device.select({
+ iPhoneX: IPHONE_X_NOTCH_PADDING,
+ iPhoneXR: IPHONE_XR_NOTCH_PADDING,
+ default: 0,
+ }),
},
container: {
[INCLUDE]: ['fillParent'],
@@ -1552,6 +1559,7 @@ export default (variables = defaultThemeVariables) => ({
position: 'absolute',
top: Device.select({
iPhoneX: 6,
+ iPhoneXR: 8,
default: Platform.OS === 'android' ? 0 : -4,
}),
left: 0,
@@ -1560,12 +1568,17 @@ export default (variables = defaultThemeVariables) => ({
},
statusBar: {
backgroundColor: variables.statusBarColor,
- height: IPHONE_X_NOTCH_PADDING,
+ height: Device.select({
+ iPhoneX: IPHONE_X_NOTCH_PADDING,
+ iPhoneXR: IPHONE_XR_NOTCH_PADDING,
+ default: 0,
+ }),
},
screenBackground: variables.backgroundColor,
navigationBarImage: {
marginTop: Device.select({
iPhoneX: IPHONE_X_NOTCH_PADDING,
+ iPhoneXR: IPHONE_XR_NOTCH_PADDING,
default: 0,
}),
flex: 1,
@@ -1977,6 +1990,11 @@ export default (variables = defaultThemeVariables) => ({
text: {
},
},
+ 'shoutem.ui.SimpleHtml': {
+ container: {
+ padding: variables.mediumGutter,
+ },
+ },
'shoutem.ui.Html': {
container: {
backgroundColor: variables.paperColor,
@@ -2458,6 +2476,10 @@ export default (variables = defaultThemeVariables) => ({
},
'shoutem.ui.Lightbox': {
+ '.container': {
+ flex: 1,
+ resizeMode: 'contain',
+ },
'shoutem.ui.Image': {
'.preview': {
flex: 1,