Repository: callstack/react-native-paper
Pull request #439 (2018-07-04 14:11:22)

BREAKING: remove Portal wrapper from components
Currently, we wrap certain components such as FAB.Group and Snackbar in Portal by default.
This means they are always rendered on top of everything and there's no way to control it.
This makes it hard to integrate with navigation libraries such as React Navigation.
The PR removes the Portal wrapper by default and exports PortalHost so users can control where the components are rendered.

In future React Navigation could provide an API to render things on top of the screen and users would be able to take advantage of it.


callstack-bot: Hey @satya164, thank you for your pull request 🤗. The documentation from this branch can be viewed [here](https://3693-71323749-gh.circle-artifacts.com/0/docs/index.html).

Patch:
diff --git a/example/src/FABExample.js b/example/src/FABExample.js
index dbdacfa8e..f7684cecd 100644
--- a/example/src/FABExample.js
+++ b/example/src/FABExample.js
@@ -2,7 +2,7 @@
 
 import * as React from 'react';
 import { View, StyleSheet } from 'react-native';
-import { Colors, FAB, withTheme } from 'react-native-paper';
+import { Colors, FAB, Portal, withTheme } from 'react-native-paper';
 import type { Theme } from 'react-native-paper/types';
 
 type Props = {
@@ -38,22 +38,24 @@ class ButtonExample extends React.Component<Props, State> {
             style={styles.fab}
             onPress={() => {}}
           />
-          <FAB.Group
-            open={this.state.open}
-            icon={this.state.open ? 'today' : 'add'}
-            actions={[
-              { icon: 'add', onPress: () => {} },
-              { icon: 'star', label: 'Star', onPress: () => {} },
-              { icon: 'email', label: 'Email', onPress: () => {} },
-              { icon: 'notifications', label: 'Remind', onPress: () => {} },
-            ]}
-            onStateChange={({ open }) => this.setState({ open })}
-            onPress={() => {
-              if (this.state.open) {
-                // do something if the speed dial is open
-              }
-            }}
-          />
+          <Portal>
+            <FAB.Group
+              open={this.state.open}
+              icon={this.state.open ? 'today' : 'add'}
+              actions={[
+                { icon: 'add', onPress: () => {} },
+                { icon: 'star', label: 'Star', onPress: () => {} },
+                { icon: 'email', label: 'Email', onPress: () => {} },
+                { icon: 'notifications', label: 'Remind', onPress: () => {} },
+              ]}
+              onStateChange={({ open }) => this.setState({ open })}
+              onPress={() => {
+                if (this.state.open) {
+                  // do something if the speed dial is open
+                }
+              }}
+            />
+          </Portal>
         </View>
       </View>
     );
diff --git a/src/components/Dialog/Dialog.js b/src/components/Dialog/Dialog.js
index bb3b6722c..67039fe5c 100644
--- a/src/components/Dialog/Dialog.js
+++ b/src/components/Dialog/Dialog.js
@@ -33,6 +33,7 @@ type Props = {
 
 /**
  * Dialogs inform users about a specific task and may contain critical information, require decisions, or involve multiple tasks.
+ * To render the `Dialog` above other components, you'll need to wrap it with the [`Portal`](portal.html) component.
  *
  *  <div class="screenshots">
  *   <img class="medium" src="screenshots/dialog-1.png" />
@@ -43,7 +44,7 @@ type Props = {
  * ```js
  * import * as React from 'react';
  * import { View } from 'react-native';
- * import { Button, Dialog, Paragraph } from 'react-native-paper';
+ * import { Button, Paragraph, Dialog, Portal } from 'react-native-paper';
  *
  * export default class MyComponent extends React.Component {
  *   state = {
@@ -58,18 +59,19 @@ type Props = {
  *     return (
  *       <View>
  *         <Button onPress={this._showDialog}>Show Dialog</Button>
- *         <Dialog
- *            visible={this.state.visible}
- *            onDismiss={this._hideDialog}
- *         >
- *           <Dialog.Title>Alert</Dialog.Title>
- *           <Dialog.Content>
- *             <Paragraph>This is simple dialog</Paragraph>
- *           </Dialog.Content>
- *           <Dialog.Actions>
- *             <Button onPress={this._hideDialog}>Done</Button>
- *           </Dialog.Actions>
- *         </Dialog>
+ *         <Portal>
+ *           <Dialog
+ *              visible={this.state.visible}
+ *              onDismiss={this._hideDialog}>
+ *             <Dialog.Title>Alert</Dialog.Title>
+ *             <Dialog.Content>
+ *               <Paragraph>This is simple dialog</Paragraph>
+ *             </Dialog.Content>
+ *             <Dialog.Actions>
+ *               <Button onPress={this._hideDialog}>Done</Button>
+ *             </Dialog.Actions>
+ *           </Dialog>
+ *         </Portal>
  *       </View>
  *     );
  *   }
diff --git a/src/components/Dialog/DialogActions.js b/src/components/Dialog/DialogActions.js
index d675709c2..33b5b4037 100644
--- a/src/components/Dialog/DialogActions.js
+++ b/src/components/Dialog/DialogActions.js
@@ -17,7 +17,7 @@ type Props = {
  * ## Usage
  * ```js
  * import * as React from 'react';
- * import { Button, Dialog } from 'react-native-paper';
+ * import { Button, Dialog, Portal } from 'react-native-paper';
  *
  * export default class MyComponent extends React.Component {
  *   state = {
@@ -28,14 +28,16 @@ type Props = {
  *
  *   render() {
  *     return (
- *       <Dialog
- *         visible={this.state.visible}
- *         onDismiss={this._hideDialog}>
- *         <Dialog.Actions>
- *           <Button onPress={() => console.log("Cancel"))}>Cancel</Button>
- *           <Button onPress={() => console.log("Ok")}>Ok</Button>
- *         </Dialog.Actions>
- *       </Dialog>
+ *       <Portal>
+ *         <Dialog
+ *           visible={this.state.visible}
+ *           onDismiss={this._hideDialog}>
+ *           <Dialog.Actions>
+ *             <Button onPress={() => console.log("Cancel"))}>Cancel</Button>
+ *             <Button onPress={() => console.log("Ok")}>Ok</Button>
+ *           </Dialog.Actions>
+ *         </Dialog>
+ *       </Portal>
  *     );
  *   }
  * }
diff --git a/src/components/Dialog/DialogContent.js b/src/components/Dialog/DialogContent.js
index 41e0d6279..599305ac2 100644
--- a/src/components/Dialog/DialogContent.js
+++ b/src/components/Dialog/DialogContent.js
@@ -17,7 +17,7 @@ type Props = {
  * ## Usage
  * ```js
  * import * as React from 'react';
- * import { Dialog, Paragraph } from 'react-native-paper';
+ * import { Paragraph, Dialog, Portal } from 'react-native-paper';
  *
  * export default class MyComponent extends React.Component {
  *   state = {
@@ -28,13 +28,15 @@ type Props = {
  *
  *   render() {
  *     return (
- *       <Dialog
- *         visible={this.state.visible}
- *         onDismiss={this._hideDialog}>
- *         <Dialog.Content>
- *           <Paragraph>This is simple dialog</Paragraph>
- *         </Dialog.Content>
- *       </Dialog>
+ *       <Portal>
+ *         <Dialog
+ *           visible={this.state.visible}
+ *           onDismiss={this._hideDialog}>
+ *           <Dialog.Content>
+ *             <Paragraph>This is simple dialog</Paragraph>
+ *           </Dialog.Content>
+ *         </Dialog>
+ *       </Portal>
  *     );
  *   }
  * }
diff --git a/src/components/Dialog/DialogScrollArea.js b/src/components/Dialog/DialogScrollArea.js
index 5640694d2..e42034401 100644
--- a/src/components/Dialog/DialogScrollArea.js
+++ b/src/components/Dialog/DialogScrollArea.js
@@ -19,7 +19,7 @@ type Props = {
  * ```js
  * import * as React from 'react';
  * import { ScrollView } from 'react-native';
- * import { Dialog } from 'react-native-paper';
+ * import { Dialog, Portal } from 'react-native-paper';
  *
  * export default class MyComponent extends React.Component {
  *   state = {
@@ -30,15 +30,17 @@ type Props = {
  *
  *   render() {
  *     return (
- *       <Dialog
- *         visible={this.state.visible}
- *         onDismiss={this._hideDialog}>
- *         <Dialog.ScrollArea>
- *           <ScrollView contentContainerStyle={{ paddingHorizontal: 24 }}>
- *             This is a scrollable area
- *           </ScrollView>
- *         </Dialog.ScrollArea>
- *       </Dialog>
+ *       <Portal>
+ *         <Dialog
+ *           visible={this.state.visible}
+ *           onDismiss={this._hideDialog}>
+ *           <Dialog.ScrollArea>
+ *             <ScrollView contentContainerStyle={{ paddingHorizontal: 24 }}>
+ *               This is a scrollable area
+ *             </ScrollView>
+ *           </Dialog.ScrollArea>
+ *         </Dialog>
+ *       </Portal>
  *     );
  *   }
  * }
diff --git a/src/components/Dialog/DialogTitle.js b/src/components/Dialog/DialogTitle.js
index c2e5d6516..4a0c952b6 100644
--- a/src/components/Dialog/DialogTitle.js
+++ b/src/components/Dialog/DialogTitle.js
@@ -24,7 +24,7 @@ type Props = {
  * ## Usage
  * ```js
  * import * as React from 'react';
- * import { Dialog, Paragraph } from 'react-native-paper';
+ * import { Paragraph, Dialog, Portal } from 'react-native-paper';
  *
  * export default class MyComponent extends React.Component {
  *   state = {
@@ -35,14 +35,16 @@ type Props = {
  *
  *   render() {
  *     return (
- *       <Dialog
- *         visible={this.state.visible}
- *         onDismiss={this._hideDialog}>
- *         <Dialog.Title>This is a title</Dialog.Title>
- *         <Dialog.Content>
- *           <Paragraph>This is simple dialog</Paragraph>
- *         </Dialog.Content>
- *       </Dialog>
+ *       <Portal>
+ *         <Dialog
+ *           visible={this.state.visible}
+ *           onDismiss={this._hideDialog}>
+ *           <Dialog.Title>This is a title</Dialog.Title>
+ *           <Dialog.Content>
+ *             <Paragraph>This is simple dialog</Paragraph>
+ *           </Dialog.Content>
+ *         </Dialog>
+ *       </Portal>
  *     );
  *   }
  * }
diff --git a/src/components/FAB/FABGroup.js b/src/components/FAB/FABGroup.js
index 9ee86702c..0bd59f7fe 100644
--- a/src/components/FAB/FABGroup.js
+++ b/src/components/FAB/FABGroup.js
@@ -13,7 +13,6 @@ import color from 'color';
 import FAB from './FAB';
 import Text from '../Typography/Text';
 import Card from '../Card/Card';
-import ThemedPortal from '../Portal/ThemedPortal';
 import withTheme from '../../core/withTheme';
 import type { Theme } from '../../types';
 import type { IconSource } from '../Icon';
@@ -79,6 +78,7 @@ type State = {
 
 /**
  * A component to display a stack of FABs with related actions in a speed dial.
+ * To render the group above other components, you'll need to wrap it with the [`Portal`](portal.html) component.
  *
  * <div class="screenshots">
  *   <img src="screenshots/fab-group.png" />
@@ -86,8 +86,8 @@ type State = {
  *
  * ## Usage
  * ```js
- * import React from 'react';
- * import { FAB, StyleSheet } from 'react-native-paper';
+ * import * as React from 'react';
+ * import { FAB, Portal, StyleSheet } from 'react-native-paper';
  *
  * export default class MyComponent extends React.Component {
  *   state = {
@@ -96,22 +96,24 @@ type State = {
  *
  *   render() {
  *     return (
- *       <FAB.Group
- *         open={this.state.open}
- *         icon={this.state.open ? 'today' : 'add'}
- *         actions={[
- *           { icon: 'add', onPress: () => {} },
- *           { icon: 'star', label: 'Star', onPress: () => {} },
- *           { icon: 'email', label: 'Email', onPress: () => {} },
- *           { icon: 'notifications', label: 'Remind', onPress: () => {} },
- *         ]}
- *         onStateChange={({ open }) => this.setState({ open })}
- *         onPress={() => {
- *           if (this.state.open) {
- *             // do something if the speed dial is open
- *           }
- *         }}
- *       />
+ *       <Portal>
+ *         <FAB.Group
+ *           open={this.state.open}
+ *           icon={this.state.open ? 'today' : 'add'}
+ *           actions={[
+ *             { icon: 'add', onPress: () => {} },
+ *             { icon: 'star', label: 'Star', onPress: () => {} },
+ *             { icon: 'email', label: 'Email', onPress: () => {} },
+ *             { icon: 'notifications', label: 'Remind', onPress: () => {} },
+ *           ]}
+ *           onStateChange={({ open }) => this.setState({ open })}
+ *           onPress={() => {
+ *             if (this.state.open) {
+ *               // do something if the speed dial is open
+ *             }
+ *           }}
+ *         />
+ *       </Portal>
  *     );
  *   }
  * }
@@ -219,64 +221,38 @@ class FABGroup extends React.Component<Props, State> {
     );
 
     return (
-      <ThemedPortal>
+      <View pointerEvents="box-none" style={[styles.container, style]}>
         {open ? <StatusBar barStyle="light-content" /> : null}
-        <View pointerEvents="box-none" style={[styles.container, style]}>
-          <TouchableWithoutFeedback onPress={this._close}>
+        <TouchableWithoutFeedback onPress={this._close}>
+          <Animated.View
+            pointerEvents={open ? 'auto' : 'none'}
+            style={[
+              styles.backdrop,
+              {
+                opacity: backdropOpacity,
+                backgroundColor: 'rgba(0, 0, 0, 0.4)',
+              },
+            ]}
+          />
+        </TouchableWithoutFeedback>
+        <View pointerEvents={open ? 'box-none' : 'none'}>
+          {actions.map((it, i) => (
             <Animated.View
-              pointerEvents={open ? 'auto' : 'none'}
+                key={i} //eslint-disable-line
               style={[
-                styles.backdrop,
                 {
-                  opacity: backdropOpacity,
-                  backgroundColor: 'rgba(0, 0, 0, 0.4)',
+                  opacity: opacities[i],
                 },
               ]}
-            />
-          </TouchableWithoutFeedback>
-          <View pointerEvents={open ? 'box-none' : 'none'}>
-            {actions.map((it, i) => (
-              <Animated.View
-                key={i} //eslint-disable-line
-                style={[
-                  {
-                    opacity: opacities[i],
-                  },
-                ]}
-                pointerEvents="box-none"
-              >
-                <View style={styles.item} pointerEvents="box-none">
-                  {it.label && (
-                    <Card
-                      style={[
-                        styles.label,
-                        {
-                          transform: [{ scale: scales[i] }],
-                        },
-                      ]}
-                      onPress={() => {
-                        it.onPress();
-                        this._close();
-                      }}
-                      accessibilityLabel={
-                        it.accessibilityLabel !== 'undefined'
-                          ? it.accessibilityLabel
-                          : it.label
-                      }
-                      accessibilityTraits="button"
-                      accessibilityComponentType="button"
-                    >
-                      <Text style={{ color: labelColor }}>{it.label}</Text>
-                    </Card>
-                  )}
-                  <FAB
-                    small
-                    icon={it.icon}
-                    color={it.color}
+              pointerEvents="box-none"
+            >
+              <View style={styles.item} pointerEvents="box-none">
+                {it.label && (
+                  <Card
                     style={[
+                      styles.label,
                       {
                         transform: [{ scale: scales[i] }],
-                        backgroundColor: theme.colors.surface,
                       },
                     ]}
                     onPress={() => {
@@ -284,31 +260,55 @@ class FABGroup extends React.Component<Props, State> {
                       this._close();
                     }}
                     accessibilityLabel={
-                      typeof it.accessibilityLabel !== 'undefined'
+                      it.accessibilityLabel !== 'undefined'
                         ? it.accessibilityLabel
                         : it.label
                     }
                     accessibilityTraits="button"
                     accessibilityComponentType="button"
-                  />
-                </View>
-              </Animated.View>
-            ))}
-          </View>
-          <FAB
-            onPress={() => {
-              onPress && onPress();
-              this._toggle();
-            }}
-            icon={icon}
-            color={this.props.color}
-            accessibilityLabel={accessibilityLabel}
-            accessibilityTraits="button"
-            accessibilityComponentType="button"
-            style={styles.fab}
-          />
+                  >
+                    <Text style={{ color: labelColor }}>{it.label}</Text>
+                  </Card>
+                )}
+                <FAB
+                  small
+                  icon={it.icon}
+                  color={it.color}
+                  style={[
+                    {
+                      transform: [{ scale: scales[i] }],
+                      backgroundColor: theme.colors.surface,
+                    },
+                  ]}
+                  onPress={() => {
+                    it.onPress();
+                    this._close();
+                  }}
+                  accessibilityLabel={
+                    typeof it.accessibilityLabel !== 'undefined'
+                      ? it.accessibilityLabel
+                      : it.label
+                  }
+                  accessibilityTraits="button"
+                  accessibilityComponentType="button"
+                />
+              </View>
+            </Animated.View>
+          ))}
         </View>
-      </ThemedPortal>
+        <FAB
+          onPress={() => {
+            onPress && onPress();
+            this._toggle();
+          }}
+          icon={icon}
+          color={this.props.color}
+          accessibilityLabel={accessibilityLabel}
+          accessibilityTraits="button"
+          accessibilityComponentType="button"
+          style={styles.fab}
+        />
+      </View>
     );
   }
 }
diff --git a/src/components/Modal.js b/src/components/Modal.js
index fc330298d..2de48f1fd 100644
--- a/src/components/Modal.js
+++ b/src/components/Modal.js
@@ -10,7 +10,6 @@ import {
   BackHandler,
 } from 'react-native';
 import { polyfill } from 'react-lifecycles-compat';
-import ThemedPortal from './Portal/ThemedPortal';
 
 type Props = {
   /**
@@ -38,11 +37,12 @@ type State = {
 
 /**
  * The Modal component is a simple way to present content above an enclosing view.
+ * To render the `Modal` above other components, you'll need to wrap it with the [`Portal`](portal.html) component.
  *
  * ## Usage
  * ```js
  * import * as React from 'react';
- * import { Modal, Text } from 'react-native-paper';
+ * import { Modal, Portal, Text } from 'react-native-paper';
  *
  * export default class MyComponent extends React.Component {
  *   state = {
@@ -55,9 +55,11 @@ type State = {
  *   render() {
  *     const { visible } = this.state;
  *     return (
- *       <Modal visible={visible}>
- *         <Text>Example Modal</Text>
- *       </Modal>
+ *       <Portal>
+ *         <Modal visible={visible}>
+ *           <Text>Example Modal</Text>
+ *         </Modal>
+ *       </Portal>
  *     );
  *   }
  * }
@@ -136,28 +138,26 @@ class Modal extends React.Component<Props, State> {
 
     const { children, dismissable } = this.props;
     return (
-      <ThemedPortal>
-        <Animated.View
-          accessibilityViewIsModal
-          accessibilityLiveRegion="polite"
-          style={[{ opacity: this.state.opacity }, styles.wrapper]}
-        >
-          <View
-            style={[
-              StyleSheet.absoluteFill,
-              { backgroundColor: 'rgba(0, 0, 0, .5)' },
-            ]}
-          />
-          {dismissable && (
-            <TouchableWithoutFeedback onPress={this._hideModal}>
-              <View style={StyleSheet.absoluteFill} />
-            </TouchableWithoutFeedback>
-          )}
-          <Animated.View style={[{ opacity: this.state.opacity }]}>
-            {children}
-          </Animated.View>
+      <Animated.View
+        accessibilityViewIsModal
+        accessibilityLiveRegion="polite"
+        style={[{ opacity: this.state.opacity }, styles.wrapper]}
+      >
+        <View
+          style={[
+            StyleSheet.absoluteFill,
+            { backgroundColor: 'rgba(0, 0, 0, .5)' },
+          ]}
+        />
+        {dismissable && (
+          <TouchableWithoutFeedback onPress={this._hideModal}>
+            <View style={StyleSheet.absoluteFill} />
+          </TouchableWithoutFeedback>
+        )}
+        <Animated.View style={[{ opacity: this.state.opacity }]}>
+          {children}
         </Animated.View>
-      </ThemedPortal>
+      </Animated.View>
     );
   }
 }
diff --git a/src/components/Portal/Portal.js b/src/components/Portal/Portal.js
index 8c3158a0b..a20475219 100644
--- a/src/components/Portal/Portal.js
+++ b/src/components/Portal/Portal.js
@@ -3,22 +3,61 @@
 
 import * as React from 'react';
 import PortalConsumer from './PortalConsumer';
-import { PortalContext } from './PortalHost';
+import PortalHost, { PortalContext } from './PortalHost';
+import ThemeProvider from '../../core/ThemeProvider';
+import withTheme from '../../core/withTheme';
+import type { Theme } from '../../types';
 
 type Props = {
   /**
    * Content of the `Portal`.
    */
-  children: React.Element<*>,
+  children: React.Node,
+  /**
+   * @optional
+   */
+  theme: Theme,
 };
 
 /**
  * Portal allows to render a component at a different place in the parent tree.
+ * You can use it to render content which should appear above other elements, similar to `Modal`.
+ * It requires a [`Portal.Host`](portal-host.html) component to be rendered somewhere in the parent tree.
+ *
+ * ## Usage
+ * ```js
+ * import * as React from 'react';
+ * import { Portal, Text } from 'react-native-paper';
+ *
+ * export default class MyComponent extends React.Component {
+ *   render() {
+ *     const { visible } = this.state;
+ *     return (
+ *       <Portal>
+ *         <Text>This is rendered at a different place</Text>
+ *       </Portal>
+ *     );
+ *   }
+ * }
+ * ```
  */
-export default function Portal({ children }: Props) {
-  return (
-    <PortalContext.Consumer>
-      {manager => <PortalConsumer manager={manager}>{children}</PortalConsumer>}
-    </PortalContext.Consumer>
-  );
+class Portal extends React.Component<Props> {
+  // @component ./PortalHost.js
+  static Host = PortalHost;
+
+  render() {
+    const { children, theme } = this.props;
+
+    return (
+      <PortalContext.Consumer>
+        {manager => (
+          <PortalConsumer manager={manager}>
+            <ThemeProvider theme={theme}>{children}</ThemeProvider>
+          </PortalConsumer>
+        )}
+      </PortalContext.Consumer>
+    );
+  }
 }
+
+export default withTheme(Portal);
diff --git a/src/components/Portal/PortalHost.js b/src/components/Portal/PortalHost.js
index c0a3140f5..a119a73bc 100644
--- a/src/components/Portal/PortalHost.js
+++ b/src/components/Portal/PortalHost.js
@@ -24,9 +24,31 @@ export const PortalContext: Context<PortalMethods> = createReactContext(
 );
 
 /**
- * Portal host is the component which actually renders all Portals.
+ * Portal host renders all of its children `Portal` elements.
+ * For example, you can wrap a screen in `Portal.Host` to render items above the screen.
+ * If you're using the `Provider` component, it already includes `Portal.Host`.
+ *
+ * ## Usage
+ * ```js
+ * import * as React from 'react';
+ * import { Portal, StyleSheet } from 'react-native-paper';
+ *
+ * export default class MyComponent extends React.Component {
+ *   render() {
+ *     return (
+ *       <Portal.Host>
+ *         <App />
+ *       </Portal.Host>
+ *     );
+ *   }
+ * }
+ * ```
+ *
+ * Here any `Portal` elements under `<App />` are rendered alongside `<App />` and will appear above `<App />` like a `Modal`.
  */
 export default class PortalHost extends React.Component<Props> {
+  static displayName = 'Portal.Host';
+
   componentDidMount() {
     const manager = this._manager;
     const queue = this._queue;
diff --git a/src/components/Portal/ThemedPortal.js b/src/components/Portal/ThemedPortal.js
deleted file mode 100644
index f0eb099df..000000000
--- a/src/components/Portal/ThemedPortal.js
+++ /dev/null
@@ -1,29 +0,0 @@
-/* @flow */
-
-import * as React from 'react';
-import Portal from './Portal';
-import ThemeProvider from '../../core/ThemeProvider';
-import withTheme from '../../core/withTheme';
-import type { Theme } from '../../types';
-
-type Props = {
-  children: React.Node,
-  theme: Theme,
-};
-
-/**
- * Themed portal is a special portal which preserves the theme in the context.
- */
-class ThemedPortal extends React.Component<Props> {
-  render() {
-    return (
-      <Portal {...this.props}>
-        <ThemeProvider theme={this.props.theme}>
-          {this.props.children}
-        </ThemeProvider>
-      </Portal>
-    );
-  }
-}
-
-export default withTheme(ThemedPortal);
diff --git a/src/components/Searchbar.js b/src/components/Searchbar.js
index 854f00fed..27afb993f 100644
--- a/src/components/Searchbar.js
+++ b/src/components/Searchbar.js
@@ -47,7 +47,7 @@ type Props = {
  *
  * ## Usage
  * ```js
- * import React from 'react';
+ * import * as React from 'react';
  * import { Searchbar } from 'react-native-paper';
  *
  * export default class MyComponent extends React.Component {
diff --git a/src/components/Snackbar.js b/src/components/Snackbar.js
index e2d5a7803..72bb4becd 100644
--- a/src/components/Snackbar.js
+++ b/src/components/Snackbar.js
@@ -5,7 +5,6 @@ import { StyleSheet, Animated, View, SafeAreaView } from 'react-native';
 
 import Button from './Button';
 import Text from './Typography/Text';
-import ThemedPortal from './Portal/ThemedPortal';
 import withTheme from '../core/withTheme';
 import { white } from '../styles/colors';
 import type { Theme } from '../types';
@@ -60,8 +59,9 @@ const DURATION_LONG = 10000;
  *
  * ## Usage
  * ```js
- * import React from 'react';
- * import { Snackbar, StyleSheet } from 'react-native-paper';
+ * import * as React from 'react';
+ * import { StyleSheet } from 'react-native';
+ * import { Snackbar } from 'react-native-paper';
  *
  * export default class MyComponent extends React.Component {
  *   state = {
@@ -173,50 +173,48 @@ class Snackbar extends React.Component<Props, State> {
     const { colors, roundness } = theme;
 
     return (
-      <ThemedPortal>
-        <SafeAreaView pointerEvents="box-none" style={styles.wrapper}>
-          <Animated.View
+      <SafeAreaView pointerEvents="box-none" style={styles.wrapper}>
+        <Animated.View
+          pointerEvents="box-none"
+          accessibilityLiveRegion="polite"
+          style={{
+            opacity: this.state.opacity,
+            transform: [
+              {
+                scale: visible
+                  ? this.state.opacity.interpolate({
+                      inputRange: [0, 1],
+                      outputRange: [0.9, 1],
+                    })
+                  : 1,
+              },
+            ],
+          }}
+        >
+          <View
             pointerEvents="box-none"
-            accessibilityLiveRegion="polite"
-            style={{
-              opacity: this.state.opacity,
-              transform: [
-                {
-                  scale: visible
-                    ? this.state.opacity.interpolate({
-                        inputRange: [0, 1],
-                        outputRange: [0.9, 1],
-                      })
-                    : 1,
-                },
-              ],
-            }}
+            style={[styles.container, { borderRadius: roundness }, style]}
           >
-            <View
-              pointerEvents="box-none"
-              style={[styles.container, { borderRadius: roundness }, style]}
-            >
-              <Text style={[styles.content, { marginRight: action ? 0 : 16 }]}>
-                {children}
-              </Text>
-              {action ? (
-                <Button
-                  onPress={() => {
-                    action.onPress();
-                    onDismiss();
-                  }}
-                  style={styles.button}
-                  color={colors.accent}
-                  compact
-                  mode="text"
-                >
-                  {action.label.toUpperCase()}
-                </Button>
-              ) : null}
-            </View>
-          </Animated.View>
-        </SafeAreaView>
-      </ThemedPortal>
+            <Text style={[styles.content, { marginRight: action ? 0 : 16 }]}>
+              {children}
+            </Text>
+            {action ? (
+              <Button
+                onPress={() => {
+                  action.onPress();
+                  onDismiss();
+                }}
+                style={styles.button}
+                color={colors.accent}
+                compact
+                mode="text"
+              >
+                {action.label.toUpperCase()}
+              </Button>
+            ) : null}
+          </View>
+        </Animated.View>
+      </SafeAreaView>
     );
   }
 }
diff --git a/src/core/Provider.js b/src/core/Provider.js
index 0ffc119cd..c398e39c5 100644
--- a/src/core/Provider.js
+++ b/src/core/Provider.js
@@ -2,7 +2,7 @@
 
 import * as React from 'react';
 import ThemeProvider from './ThemeProvider';
-import PortalHost from '../components/Portal/PortalHost';
+import Portal from '../components/Portal/Portal';
 import type { Theme } from '../types';
 
 type Props = {
@@ -13,11 +13,11 @@ type Props = {
 export default class Provider extends React.Component<Props> {
   render() {
     return (
-      <PortalHost>
+      <Portal.Host>
         <ThemeProvider theme={this.props.theme}>
           {this.props.children}
         </ThemeProvider>
-      </PortalHost>
+      </Portal.Host>
     );
   }
 }
diff --git a/src/index.js b/src/index.js
index 25bd52be6..f88c44622 100644
--- a/src/index.js
+++ b/src/index.js
@@ -23,6 +23,7 @@ export { default as HelperText } from './components/HelperText';
 export { default as IconButton } from './components/IconButton';
 export { default as ListSection } from './components/List/ListSection';
 export { default as Modal } from './components/Modal';
+export { default as Portal } from './components/Portal/Portal';
 export { default as ProgressBar } from './components/ProgressBar/ProgressBar';
 export { default as RadioButton } from './components/RadioButton';
 export { default as Searchbar } from './components/Searchbar';


Test patch:
diff --git a/src/components/__tests__/Portal.test.js b/src/components/__tests__/Portal.test.js
index 019a1483b..d4235208c 100644
--- a/src/components/__tests__/Portal.test.js
+++ b/src/components/__tests__/Portal.test.js
@@ -3,18 +3,17 @@
 import * as React from 'react';
 import renderer from 'react-test-renderer';
 import { Text } from 'react-native';
-import PortalHost from '../Portal/PortalHost';
 import Portal from '../Portal/Portal';
 
 it('renders portal with siblings', () => {
   const tree = renderer
     .create(
-      <PortalHost>
+      <Portal.Host>
         <Text>Outside content</Text>
         <Portal>
           <Text>Portal content</Text>
         </Portal>
-      </PortalHost>
+      </Portal.Host>
     )
     .toJSON();
 
diff --git a/src/components/__tests__/Snackbar.test.js b/src/components/__tests__/Snackbar.test.js
index 0d8d2db46..3e673a324 100644
--- a/src/components/__tests__/Snackbar.test.js
+++ b/src/components/__tests__/Snackbar.test.js
@@ -4,18 +4,15 @@ import * as React from 'react';
 import renderer from 'react-test-renderer';
 import { Text } from 'react-native';
 import Snackbar from '../Snackbar';
-import PortalHost from '../Portal/PortalHost';
 
 jest.useFakeTimers();
 
 it('renders snackbar with content', () => {
   const tree = renderer
     .create(
-      <PortalHost>
-        <Snackbar visible onDismiss={jest.fn()}>
-          Snackbar content
-        </Snackbar>
-      </PortalHost>
+      <Snackbar visible onDismiss={jest.fn()}>
+        Snackbar content
+      </Snackbar>
     )
     .toJSON();
 
@@ -25,11 +22,9 @@ it('renders snackbar with content', () => {
 it('renders not visible snackbar with content', () => {
   const tree = renderer
     .create(
-      <PortalHost>
-        <Snackbar visible={false} onDismiss={jest.fn()}>
-          Snackbar content
-        </Snackbar>
-      </PortalHost>
+      <Snackbar visible={false} onDismiss={jest.fn()}>
+        Snackbar content
+      </Snackbar>
     )
     .toJSON();
 
@@ -39,11 +34,9 @@ it('renders not visible snackbar with content', () => {
 it('renders snackbar with Text as a child', () => {
   const tree = renderer
     .create(
-      <PortalHost>
-        <Snackbar visible onDismiss={jest.fn()}>
-          <Text>Snackbar content</Text>
-        </Snackbar>
-      </PortalHost>
+      <Snackbar visible onDismiss={jest.fn()}>
+        <Text>Snackbar content</Text>
+      </Snackbar>
     )
     .toJSON();
 
@@ -53,15 +46,13 @@ it('renders snackbar with Text as a child', () => {
 it('renders snackbar with action button', () => {
   const tree = renderer
     .create(
-      <PortalHost>
-        <Snackbar
-          visible
-          onDismiss={() => {}}
-          action={{ label: 'Undo', onPress: jest.fn() }}
-        >
-          Snackbar content
-        </Snackbar>
-      </PortalHost>
+      <Snackbar
+        visible
+        onDismiss={() => {}}
+        action={{ label: 'Undo', onPress: jest.fn() }}
+      >
+        Snackbar content
+      </Snackbar>
     )
     .toJSON();
 
diff --git a/src/components/__tests__/__snapshots__/Snackbar.test.js.snap b/src/components/__tests__/__snapshots__/Snackbar.test.js.snap
index 1c90d1eb6..0dcd6d99b 100644
--- a/src/components/__tests__/__snapshots__/Snackbar.test.js.snap
+++ b/src/components/__tests__/__snapshots__/Snackbar.test.js.snap
@@ -1,564 +1,512 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
 exports[`renders not visible snackbar with content 1`] = `
-<View
+<RCTSafeAreaView
   pointerEvents="box-none"
   style={
     Object {
       "bottom": 0,
-      "left": 0,
       "position": "absolute",
-      "right": 0,
-      "top": 0,
+      "width": "100%",
     }
   }
 >
-  <RCTSafeAreaView
+  <View
+    accessibilityLiveRegion="polite"
     pointerEvents="box-none"
     style={
       Object {
-        "bottom": 0,
-        "position": "absolute",
-        "width": "100%",
+        "opacity": 0,
+        "transform": Array [
+          Object {
+            "scale": 1,
+          },
+        ],
       }
     }
   >
     <View
-      accessibilityLiveRegion="polite"
       pointerEvents="box-none"
       style={
-        Object {
-          "opacity": 0,
-          "transform": Array [
-            Object {
-              "scale": 1,
-            },
-          ],
-        }
+        Array [
+          Object {
+            "alignItems": "center",
+            "backgroundColor": "#323232",
+            "borderRadius": 4,
+            "elevation": 6,
+            "flexDirection": "row",
+            "justifyContent": "space-between",
+            "margin": 8,
+          },
+          Object {
+            "borderRadius": 4,
+          },
+          undefined,
+        ]
       }
     >
-      <View
-        pointerEvents="box-none"
+      <Text
+        accessible={true}
+        allowFontScaling={true}
+        ellipsizeMode="tail"
         style={
           Array [
             Object {
-              "alignItems": "center",
-              "backgroundColor": "#323232",
-              "borderRadius": 4,
-              "elevation": 6,
-              "flexDirection": "row",
-              "justifyContent": "space-between",
-              "margin": 8,
-            },
-            Object {
-              "borderRadius": 4,
+              "color": "#000000",
+              "fontFamily": "Helvetica Neue",
             },
-            undefined,
-          ]
-        }
-      >
-        <Text
-          accessible={true}
-          allowFontScaling={true}
-          ellipsizeMode="tail"
-          style={
             Array [
               Object {
-                "color": "#000000",
-                "fontFamily": "Helvetica Neue",
-              },
-              Array [
-                Object {
-                  "color": "#ffffff",
-                  "flex": 1,
-                  "flexWrap": "wrap",
-                  "marginLeft": 16,
-                  "marginVertical": 14,
-                },
-                Object {
-                  "marginRight": 16,
-                },
-              ],
-            ]
-          }
-          theme={
-            Object {
-              "colors": Object {
-                "accent": "#03dac4",
-                "background": "#f6f6f6",
-                "disabled": "rgba(0, 0, 0, 0.26)",
-                "error": "#B00020",
-                "placeholder": "rgba(0, 0, 0, 0.38)",
-                "primary": "#6200ee",
-                "surface": "#ffffff",
-                "text": "#000000",
+                "color": "#ffffff",
+                "flex": 1,
+                "flexWrap": "wrap",
+                "marginLeft": 16,
+                "marginVertical": 14,
               },
-              "dark": false,
-              "fonts": Object {
-                "light": "HelveticaNeue-Light",
-                "medium": "HelveticaNeue-Medium",
-                "regular": "Helvetica Neue",
-                "thin": "HelveticaNeue-Thin",
+              Object {
+                "marginRight": 16,
               },
-              "roundness": 4,
-            }
+            ],
+          ]
+        }
+        theme={
+          Object {
+            "colors": Object {
+              "accent": "#03dac4",
+              "background": "#f6f6f6",
+              "disabled": "rgba(0, 0, 0, 0.26)",
+              "error": "#B00020",
+              "placeholder": "rgba(0, 0, 0, 0.38)",
+              "primary": "#6200ee",
+              "surface": "#ffffff",
+              "text": "#000000",
+            },
+            "dark": false,
+            "fonts": Object {
+              "light": "HelveticaNeue-Light",
+              "medium": "HelveticaNeue-Medium",
+              "regular": "Helvetica Neue",
+              "thin": "HelveticaNeue-Thin",
+            },
+            "roundness": 4,
           }
-        >
-          Snackbar content
-        </Text>
-      </View>
+        }
+      >
+        Snackbar content
+      </Text>
     </View>
-  </RCTSafeAreaView>
-</View>
+  </View>
+</RCTSafeAreaView>
 `;
 
 exports[`renders snackbar with Text as a child 1`] = `
-<View
+<RCTSafeAreaView
   pointerEvents="box-none"
   style={
     Object {
       "bottom": 0,
-      "left": 0,
       "position": "absolute",
-      "right": 0,
-      "top": 0,
+      "width": "100%",
     }
   }
 >
-  <RCTSafeAreaView
+  <View
+    accessibilityLiveRegion="polite"
     pointerEvents="box-none"
     style={
       Object {
-        "bottom": 0,
-        "position": "absolute",
-        "width": "100%",
+        "opacity": 0,
+        "transform": Array [
+          Object {
+            "scale": 0.9,
+          },
+        ],
       }
     }
   >
     <View
-      accessibilityLiveRegion="polite"
       pointerEvents="box-none"
       style={
-        Object {
-          "opacity": 0,
-          "transform": Array [
-            Object {
-              "scale": 0.9,
-            },
-          ],
-        }
+        Array [
+          Object {
+            "alignItems": "center",
+            "backgroundColor": "#323232",
+            "borderRadius": 4,
+            "elevation": 6,
+            "flexDirection": "row",
+            "justifyContent": "space-between",
+            "margin": 8,
+          },
+          Object {
+            "borderRadius": 4,
+          },
+          undefined,
+        ]
       }
     >
-      <View
-        pointerEvents="box-none"
+      <Text
+        accessible={true}
+        allowFontScaling={true}
+        ellipsizeMode="tail"
         style={
           Array [
             Object {
-              "alignItems": "center",
-              "backgroundColor": "#323232",
-              "borderRadius": 4,
-              "elevation": 6,
-              "flexDirection": "row",
-              "justifyContent": "space-between",
-              "margin": 8,
-            },
-            Object {
-              "borderRadius": 4,
+              "color": "#000000",
+              "fontFamily": "Helvetica Neue",
             },
-            undefined,
+            Array [
+              Object {
+                "color": "#ffffff",
+                "flex": 1,
+                "flexWrap": "wrap",
+                "marginLeft": 16,
+                "marginVertical": 14,
+              },
+              Object {
+                "marginRight": 16,
+              },
+            ],
           ]
         }
+        theme={
+          Object {
+            "colors": Object {
+              "accent": "#03dac4",
+              "background": "#f6f6f6",
+              "disabled": "rgba(0, 0, 0, 0.26)",
+              "error": "#B00020",
+              "placeholder": "rgba(0, 0, 0, 0.38)",
+              "primary": "#6200ee",
+              "surface": "#ffffff",
+              "text": "#000000",
+            },
+            "dark": false,
+            "fonts": Object {
+              "light": "HelveticaNeue-Light",
+              "medium": "HelveticaNeue-Medium",
+              "regular": "Helvetica Neue",
+              "thin": "HelveticaNeue-Thin",
+            },
+            "roundness": 4,
+          }
+        }
       >
         <Text
           accessible={true}
           allowFontScaling={true}
           ellipsizeMode="tail"
-          style={
-            Array [
-              Object {
-                "color": "#000000",
-                "fontFamily": "Helvetica Neue",
-              },
-              Array [
-                Object {
-                  "color": "#ffffff",
-                  "flex": 1,
-                  "flexWrap": "wrap",
-                  "marginLeft": 16,
-                  "marginVertical": 14,
-                },
-                Object {
-                  "marginRight": 16,
-                },
-              ],
-            ]
-          }
-          theme={
-            Object {
-              "colors": Object {
-                "accent": "#03dac4",
-                "background": "#f6f6f6",
-                "disabled": "rgba(0, 0, 0, 0.26)",
-                "error": "#B00020",
-                "placeholder": "rgba(0, 0, 0, 0.38)",
-                "primary": "#6200ee",
-                "surface": "#ffffff",
-                "text": "#000000",
-              },
-              "dark": false,
-              "fonts": Object {
-                "light": "HelveticaNeue-Light",
-                "medium": "HelveticaNeue-Medium",
-                "regular": "Helvetica Neue",
-                "thin": "HelveticaNeue-Thin",
-              },
-              "roundness": 4,
-            }
-          }
         >
-          <Text
-            accessible={true}
-            allowFontScaling={true}
-            ellipsizeMode="tail"
-          >
-            Snackbar content
-          </Text>
+          Snackbar content
         </Text>
-      </View>
+      </Text>
     </View>
-  </RCTSafeAreaView>
-</View>
+  </View>
+</RCTSafeAreaView>
 `;
 
 exports[`renders snackbar with action button 1`] = `
-<View
+<RCTSafeAreaView
   pointerEvents="box-none"
   style={
     Object {
       "bottom": 0,
-      "left": 0,
       "position": "absolute",
-      "right": 0,
-      "top": 0,
+      "width": "100%",
     }
   }
 >
-  <RCTSafeAreaView
+  <View
+    accessibilityLiveRegion="polite"
     pointerEvents="box-none"
     style={
       Object {
-        "bottom": 0,
-        "position": "absolute",
-        "width": "100%",
+        "opacity": 0,
+        "transform": Array [
+          Object {
+            "scale": 0.9,
+          },
+        ],
       }
     }
   >
     <View
-      accessibilityLiveRegion="polite"
       pointerEvents="box-none"
       style={
-        Object {
-          "opacity": 0,
-          "transform": Array [
+        Array [
+          Object {
+            "alignItems": "center",
+            "backgroundColor": "#323232",
+            "borderRadius": 4,
+            "elevation": 6,
+            "flexDirection": "row",
+            "justifyContent": "space-between",
+            "margin": 8,
+          },
+          Object {
+            "borderRadius": 4,
+          },
+          undefined,
+        ]
+      }
+    >
+      <Text
+        accessible={true}
+        allowFontScaling={true}
+        ellipsizeMode="tail"
+        style={
+          Array [
             Object {
-              "scale": 0.9,
+              "color": "#000000",
+              "fontFamily": "Helvetica Neue",
             },
-          ],
+            Array [
+              Object {
+                "color": "#ffffff",
+                "flex": 1,
+                "flexWrap": "wrap",
+                "marginLeft": 16,
+                "marginVertical": 14,
+              },
+              Object {
+                "marginRight": 0,
+              },
+            ],
+          ]
         }
-      }
-    >
+        theme={
+          Object {
+            "colors": Object {
+              "accent": "#03dac4",
+              "background": "#f6f6f6",
+              "disabled": "rgba(0, 0, 0, 0.26)",
+              "error": "#B00020",
+              "placeholder": "rgba(0, 0, 0, 0.38)",
+              "primary": "#6200ee",
+              "surface": "#ffffff",
+              "text": "#000000",
+            },
+            "dark": false,
+            "fonts": Object {
+              "light": "HelveticaNeue-Light",
+              "medium": "HelveticaNeue-Medium",
+              "regular": "Helvetica Neue",
+              "thin": "HelveticaNeue-Thin",
+            },
+            "roundness": 4,
+          }
+        }
+      >
+        Snackbar content
+      </Text>
       <View
-        pointerEvents="box-none"
         style={
           Array [
             Object {
-              "alignItems": "center",
-              "backgroundColor": "#323232",
-              "borderRadius": 4,
-              "elevation": 6,
-              "flexDirection": "row",
-              "justifyContent": "space-between",
-              "margin": 8,
+              "backgroundColor": "#ffffff",
+            },
+            Object {
+              "backgroundColor": "#ffffff",
             },
+            0,
             Object {
+              "backgroundColor": "transparent",
+              "borderColor": "transparent",
               "borderRadius": 4,
+              "borderStyle": "solid",
+              "borderWidth": 0.5,
+              "elevation": 0,
+              "marginHorizontal": 8,
+              "marginVertical": 6,
+              "minWidth": 64,
             },
-            undefined,
           ]
         }
       >
-        <Text
+        <View
+          accessibilityComponentType="button"
+          accessibilityTraits="button"
           accessible={true}
-          allowFontScaling={true}
-          ellipsizeMode="tail"
+          isTVSelectable={true}
+          onResponderGrant={[Function]}
+          onResponderMove={[Function]}
+          onResponderRelease={[Function]}
+          onResponderTerminate={[Function]}
+          onResponderTerminationRequest={[Function]}
+          onStartShouldSetResponder={[Function]}
           style={
-            Array [
-              Object {
-                "color": "#000000",
-                "fontFamily": "Helvetica Neue",
-              },
-              Array [
-                Object {
-                  "color": "#ffffff",
-                  "flex": 1,
-                  "flexWrap": "wrap",
-                  "marginLeft": 16,
-                  "marginVertical": 14,
-                },
-                Object {
-                  "marginRight": 0,
-                },
-              ],
-            ]
-          }
-          theme={
             Object {
-              "colors": Object {
-                "accent": "#03dac4",
-                "background": "#f6f6f6",
-                "disabled": "rgba(0, 0, 0, 0.26)",
-                "error": "#B00020",
-                "placeholder": "rgba(0, 0, 0, 0.38)",
-                "primary": "#6200ee",
-                "surface": "#ffffff",
-                "text": "#000000",
-              },
-              "dark": false,
-              "fonts": Object {
-                "light": "HelveticaNeue-Light",
-                "medium": "HelveticaNeue-Medium",
-                "regular": "Helvetica Neue",
-                "thin": "HelveticaNeue-Thin",
-              },
-              "roundness": 4,
+              "borderRadius": 4,
             }
           }
-        >
-          Snackbar content
-        </Text>
-        <View
-          style={
-            Array [
-              Object {
-                "backgroundColor": "#ffffff",
-              },
-              Object {
-                "backgroundColor": "#ffffff",
-              },
-              0,
-              Object {
-                "backgroundColor": "transparent",
-                "borderColor": "transparent",
-                "borderRadius": 4,
-                "borderStyle": "solid",
-                "borderWidth": 0.5,
-                "elevation": 0,
-                "marginHorizontal": 8,
-                "marginVertical": 6,
-                "minWidth": 64,
-              },
-            ]
-          }
         >
           <View
-            accessibilityComponentType="button"
-            accessibilityTraits="button"
-            accessible={true}
-            isTVSelectable={true}
-            onResponderGrant={[Function]}
-            onResponderMove={[Function]}
-            onResponderRelease={[Function]}
-            onResponderTerminate={[Function]}
-            onResponderTerminationRequest={[Function]}
-            onStartShouldSetResponder={[Function]}
             style={
               Object {
-                "borderRadius": 4,
+                "alignItems": "center",
+                "flexDirection": "row",
+                "justifyContent": "center",
               }
             }
           >
-            <View
+            <Text
+              accessible={true}
+              allowFontScaling={true}
+              ellipsizeMode="tail"
+              numberOfLines={1}
               style={
-                Object {
-                  "alignItems": "center",
-                  "flexDirection": "row",
-                  "justifyContent": "center",
-                }
-              }
-            >
-              <Text
-                accessible={true}
-                allowFontScaling={true}
-                ellipsizeMode="tail"
-                numberOfLines={1}
-                style={
+                Array [
+                  Object {
+                    "color": "#000000",
+                    "fontFamily": "Helvetica Neue",
+                  },
                   Array [
                     Object {
-                      "color": "#000000",
-                      "fontFamily": "Helvetica Neue",
+                      "letterSpacing": 1,
+                      "marginHorizontal": 16,
+                      "marginVertical": 9,
+                      "textAlign": "center",
                     },
-                    Array [
-                      Object {
-                        "letterSpacing": 1,
-                        "marginHorizontal": 16,
-                        "marginVertical": 9,
-                        "textAlign": "center",
-                      },
-                      Object {
-                        "marginHorizontal": 8,
-                      },
-                      Object {
-                        "color": "#03dac4",
-                        "fontFamily": "HelveticaNeue-Medium",
-                      },
-                      Object {
-                        "fontFamily": "HelveticaNeue-Medium",
-                      },
-                    ],
-                  ]
-                }
-                theme={
-                  Object {
-                    "colors": Object {
-                      "accent": "#03dac4",
-                      "background": "#f6f6f6",
-                      "disabled": "rgba(0, 0, 0, 0.26)",
-                      "error": "#B00020",
-                      "placeholder": "rgba(0, 0, 0, 0.38)",
-                      "primary": "#6200ee",
-                      "surface": "#ffffff",
-                      "text": "#000000",
+                    Object {
+                      "marginHorizontal": 8,
                     },
-                    "dark": false,
-                    "fonts": Object {
-                      "light": "HelveticaNeue-Light",
-                      "medium": "HelveticaNeue-Medium",
-                      "regular": "Helvetica Neue",
-                      "thin": "HelveticaNeue-Thin",
+                    Object {
+                      "color": "#03dac4",
+                      "fontFamily": "HelveticaNeue-Medium",
                     },
-                    "roundness": 4,
-                  }
+                    Object {
+                      "fontFamily": "HelveticaNeue-Medium",
+                    },
+                  ],
+                ]
+              }
+              theme={
+                Object {
+                  "colors": Object {
+                    "accent": "#03dac4",
+                    "background": "#f6f6f6",
+                    "disabled": "rgba(0, 0, 0, 0.26)",
+                    "error": "#B00020",
+                    "placeholder": "rgba(0, 0, 0, 0.38)",
+                    "primary": "#6200ee",
+                    "surface": "#ffffff",
+                    "text": "#000000",
+                  },
+                  "dark": false,
+                  "fonts": Object {
+                    "light": "HelveticaNeue-Light",
+                    "medium": "HelveticaNeue-Medium",
+                    "regular": "Helvetica Neue",
+                    "thin": "HelveticaNeue-Thin",
+                  },
+                  "roundness": 4,
                 }
-              >
-                UNDO
-              </Text>
-            </View>
+              }
+            >
+              UNDO
+            </Text>
           </View>
         </View>
       </View>
     </View>
-  </RCTSafeAreaView>
-</View>
+  </View>
+</RCTSafeAreaView>
 `;
 
 exports[`renders snackbar with content 1`] = `
-<View
+<RCTSafeAreaView
   pointerEvents="box-none"
   style={
     Object {
       "bottom": 0,
-      "left": 0,
       "position": "absolute",
-      "right": 0,
-      "top": 0,
+      "width": "100%",
     }
   }
 >
-  <RCTSafeAreaView
+  <View
+    accessibilityLiveRegion="polite"
     pointerEvents="box-none"
     style={
       Object {
-        "bottom": 0,
-        "position": "absolute",
-        "width": "100%",
+        "opacity": 0,
+        "transform": Array [
+          Object {
+            "scale": 0.9,
+          },
+        ],
       }
     }
   >
     <View
-      accessibilityLiveRegion="polite"
       pointerEvents="box-none"
       style={
-        Object {
-          "opacity": 0,
-          "transform": Array [
-            Object {
-              "scale": 0.9,
-            },
-          ],
-        }
+        Array [
+          Object {
+            "alignItems": "center",
+            "backgroundColor": "#323232",
+            "borderRadius": 4,
+            "elevation": 6,
+            "flexDirection": "row",
+            "justifyContent": "space-between",
+            "margin": 8,
+          },
+          Object {
+            "borderRadius": 4,
+          },
+          undefined,
+        ]
       }
     >
-      <View
-        pointerEvents="box-none"
+      <Text
+        accessible={true}
+        allowFontScaling={true}
+        ellipsizeMode="tail"
         style={
           Array [
             Object {
-              "alignItems": "center",
-              "backgroundColor": "#323232",
-              "borderRadius": 4,
-              "elevation": 6,
-              "flexDirection": "row",
-              "justifyContent": "space-between",
-              "margin": 8,
+              "color": "#000000",
+              "fontFamily": "Helvetica Neue",
             },
-            Object {
-              "borderRadius": 4,
-            },
-            undefined,
-          ]
-        }
-      >
-        <Text
-          accessible={true}
-          allowFontScaling={true}
-          ellipsizeMode="tail"
-          style={
             Array [
               Object {
-                "color": "#000000",
-                "fontFamily": "Helvetica Neue",
-              },
-              Array [
-                Object {
-                  "color": "#ffffff",
-                  "flex": 1,
-                  "flexWrap": "wrap",
-                  "marginLeft": 16,
-                  "marginVertical": 14,
-                },
-                Object {
-                  "marginRight": 16,
-                },
-              ],
-            ]
-          }
-          theme={
-            Object {
-              "colors": Object {
-                "accent": "#03dac4",
-                "background": "#f6f6f6",
-                "disabled": "rgba(0, 0, 0, 0.26)",
-                "error": "#B00020",
-                "placeholder": "rgba(0, 0, 0, 0.38)",
-                "primary": "#6200ee",
-                "surface": "#ffffff",
-                "text": "#000000",
+                "color": "#ffffff",
+                "flex": 1,
+                "flexWrap": "wrap",
+                "marginLeft": 16,
+                "marginVertical": 14,
               },
-              "dark": false,
-              "fonts": Object {
-                "light": "HelveticaNeue-Light",
-                "medium": "HelveticaNeue-Medium",
-                "regular": "Helvetica Neue",
-                "thin": "HelveticaNeue-Thin",
+              Object {
+                "marginRight": 16,
               },
-              "roundness": 4,
-            }
+            ],
+          ]
+        }
+        theme={
+          Object {
+            "colors": Object {
+              "accent": "#03dac4",
+              "background": "#f6f6f6",
+              "disabled": "rgba(0, 0, 0, 0.26)",
+              "error": "#B00020",
+              "placeholder": "rgba(0, 0, 0, 0.38)",
+              "primary": "#6200ee",
+              "surface": "#ffffff",
+              "text": "#000000",
+            },
+            "dark": false,
+            "fonts": Object {
+              "light": "HelveticaNeue-Light",
+              "medium": "HelveticaNeue-Medium",
+              "regular": "Helvetica Neue",
+              "thin": "HelveticaNeue-Thin",
+            },
+            "roundness": 4,
           }
-        >
-          Snackbar content
-        </Text>
-      </View>
+        }
+      >
+        Snackbar content
+      </Text>
     </View>
-  </RCTSafeAreaView>
-</View>
+  </View>
+</RCTSafeAreaView>
 `;