Repository: callstack/react-native-paper
Pull request #1078 (2019-05-20 19:32:45)

fix: move paddingHorizontal out from content style
<!-- Please provide enough information so that others can review your pull request. -->
<!-- Keep pull requests small and focused on a single change. -->

### Motivation

The ability of overriding style properties makes things more flexible. In order to achieve this within DataTableRow,  we have moved paddingHorizontal out from content style which can't be overridden, and put it in container style which can be overridden with the style class property.

### Test plan

<!-- List the steps with which we can test this change. Provide screenshots if this changes anything visual. -->


callstack-bot: Hey @jose96043, thank you for your pull request 🤗. The documentation from this branch can be viewed [here](https://10479-71323749-gh.circle-artifacts.com/0/docs/index.html). Please remember to update Typescript types if you changed API.

Patch:
diff --git a/.circleci/config.yml b/.circleci/config.yml
index 2e9c2fc2c..9590af0bd 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -65,10 +65,19 @@ jobs:
       steps:
         - attach_workspace:
             at: ~/react-native-paper
-        - run: yarn test -- --coverage
+        - restore_cache:
+            name: Restoring Jest Cache
+            keys:
+            - jest-cache-{{ .Branch }}
+            - jest-cache
+        - run: yarn test --maxWorkers=2 --coverage
         - store_artifacts:
             path: coverage
             destination: coverage
+        - save_cache:
+            paths:
+            - ./cache/jest
+            key: jest-cache-{{ .Branch }}
   build-docs:
       <<: *defaults
       steps:
diff --git a/.gitignore b/.gitignore
index e41488a13..94788a566 100644
--- a/.gitignore
+++ b/.gitignore
@@ -42,6 +42,7 @@ yarn-error.log
 # jest
 #
 coverage/
+cache/jest/
 
 # BUCK
 #
diff --git a/docs/pages/6.recommended-libraries.md b/docs/pages/6.recommended-libraries.md
new file mode 100644
index 000000000..b8faa73b6
--- /dev/null
+++ b/docs/pages/6.recommended-libraries.md
@@ -0,0 +1,21 @@
+---
+title: Recommended Libraries
+---
+
+# Recommended Libraries
+
+Our mission is to provide a full suite of well-integrated components built with Material Design in mind. However, many components already have better well maintained implementations.
+
+Here are some of the libraries we recommend:
+
+## Tabs
+
+[react-native-community/react-native-tab-view](https://github.com/react-native-community/react-native-tab-view)
+
+Material Design themed [swipeable tabs](https://material.io/design/components/tabs.html), maintained by [@satya164](https://twitter.com/satya164) and [@mosdnk](https://twitter.com/mosdnk).
+
+## Bottom sheet
+
+[osdnk/reanimated-bottom-sheet](https://github.com/osdnk/react-native-reanimated-bottom-sheet)
+
+An implementation [bottom sheet behaviour](https://material.io/design/components/sheets-bottom.html), maintained by [@mosdnk](https://twitter.com/mosdnk).
diff --git a/docs/pages/6.contributing.md b/docs/pages/7.contributing.md
similarity index 100%
rename from docs/pages/6.contributing.md
rename to docs/pages/7.contributing.md
diff --git a/example/src/Examples/ListSectionExample.js b/example/src/Examples/ListSectionExample.js
index a44097ac6..af006cddc 100644
--- a/example/src/Examples/ListSectionExample.js
+++ b/example/src/Examples/ListSectionExample.js
@@ -1,8 +1,8 @@
 /* @flow */
 
 import * as React from 'react';
-import { ScrollView, StyleSheet, Image } from 'react-native';
-import { List, Divider, withTheme, type Theme } from 'react-native-paper';
+import { ScrollView, StyleSheet, Image, View, Text } from 'react-native';
+import { Chip, List, Divider, withTheme, type Theme } from 'react-native-paper';
 
 type Props = {
   theme: Theme,
@@ -80,6 +80,42 @@ class ListSectionExample extends React.Component<Props> {
             description="Describes item 2. Example of a very very long description."
           />
         </List.Section>
+        <Divider />
+        <List.Section>
+          <List.Subheader>Custom description</List.Subheader>
+          <List.Item
+            left={() => (
+              <Image
+                source={require('../../assets/images/email-icon.png')}
+                style={styles.image}
+              />
+            )}
+            right={props => <List.Icon {...props} icon="star-border" />}
+            title="List Item 1"
+            description={({
+              ellipsizeMode,
+              color: descriptionColor,
+              fontSize,
+            }) => (
+              <View style={[styles.container, styles.column]}>
+                <Text
+                  numberOfLines={2}
+                  ellipsizeMode={ellipsizeMode}
+                  style={{ color: descriptionColor, fontSize }}
+                >
+                  React Native Paper is a high-quality, standard-compliant
+                  Material Design library that has you covered in all major
+                  use-cases.
+                </Text>
+                <View style={[styles.container, styles.row, { paddingTop: 8 }]}>
+                  <Chip icon="picture-as-pdf" onPress={() => {}}>
+                    DOCS.pdf
+                  </Chip>
+                </View>
+              </View>
+            )}
+          />
+        </List.Section>
       </ScrollView>
     );
   }
@@ -94,6 +130,12 @@ const styles = StyleSheet.create({
     width: 40,
     margin: 8,
   },
+  row: {
+    flexDirection: 'row',
+  },
+  column: {
+    flexDirection: 'column',
+  },
 });
 
 export default withTheme(ListSectionExample);
diff --git a/package.json b/package.json
index c41ec841c..b7ec322e6 100644
--- a/package.json
+++ b/package.json
@@ -106,6 +106,7 @@
   },
   "jest": {
     "preset": "react-native",
+    "cacheDirectory": "./cache/jest",
     "modulePathIgnorePatterns": [
       "<rootDir>/example/node_modules"
     ],
diff --git a/src/components/DataTable/DataTableRow.js b/src/components/DataTable/DataTableRow.js
index 4cb1a8928..cc8077d2b 100644
--- a/src/components/DataTable/DataTableRow.js
+++ b/src/components/DataTable/DataTableRow.js
@@ -51,11 +51,11 @@ const styles = StyleSheet.create({
     borderStyle: 'solid',
     borderBottomWidth: StyleSheet.hairlineWidth,
     minHeight: 48,
+    paddingHorizontal: 16,
   },
   content: {
     flex: 1,
     flexDirection: 'row',
-    paddingHorizontal: 16,
   },
 });
 
diff --git a/src/components/List/ListItem.js b/src/components/List/ListItem.js
index 51572a612..177603399 100644
--- a/src/components/List/ListItem.js
+++ b/src/components/List/ListItem.js
@@ -10,7 +10,7 @@ import type {
 import TouchableRipple from '../TouchableRipple';
 import Text from '../Typography/Text';
 import { withTheme } from '../../core/theming';
-import type { Theme, $RemoveChildren } from '../../types';
+import type { Theme, $RemoveChildren, EllipsizeProp } from '../../types';
 
 type Props = $RemoveChildren<typeof TouchableRipple> & {|
   /**
@@ -18,9 +18,15 @@ type Props = $RemoveChildren<typeof TouchableRipple> & {|
    */
   title: React.Node,
   /**
-   * Description text for the list item.
+   * Description text for the list item or callback which returns a React element to display the description.
    */
-  description?: React.Node,
+  description?:
+    | React.Node
+    | ((props: {
+        ellipsizeMode: EllipsizeProp,
+        color: string,
+        fontSize: number,
+      }) => React.Node),
   /**
    * Callback which returns a React element to display on the left side.
    */
@@ -52,11 +58,11 @@ type Props = $RemoveChildren<typeof TouchableRipple> & {|
   /**
    * Ellipsize Mode for the Title
    */
-  titleEllipsizeMode?: 'head' | 'middle' | 'tail' | 'clip',
+  titleEllipsizeMode?: EllipsizeProp,
   /**
    * Ellipsize Mode for the Description
    */
-  descriptionEllipsizeMode?: 'head' | 'middle' | 'tail' | 'clip',
+  descriptionEllipsizeMode?: EllipsizeProp,
 |};
 
 /**
@@ -87,6 +93,31 @@ type Props = $RemoveChildren<typeof TouchableRipple> & {|
 class ListItem extends React.Component<Props> {
   static displayName = 'List.Item';
 
+  renderDescription(description, descriptionColor) {
+    const { descriptionEllipsizeMode, descriptionStyle } = this.props;
+
+    return typeof description === 'string' ? (
+      <Text
+        numberOfLines={2}
+        ellipsizeMode={descriptionEllipsizeMode}
+        style={[
+          styles.description,
+          { color: descriptionColor },
+          descriptionStyle,
+        ]}
+      >
+        {description}
+      </Text>
+    ) : (
+      description &&
+        description({
+          ellipsizeMode: descriptionEllipsizeMode,
+          color: descriptionColor,
+          fontSize: styles.description.fontSize,
+        })
+    );
+  }
+
   render() {
     const {
       left,
@@ -97,9 +128,7 @@ class ListItem extends React.Component<Props> {
       theme,
       style,
       titleStyle,
-      descriptionStyle,
       titleEllipsizeMode,
-      descriptionEllipsizeMode,
       ...rest
     } = this.props;
     const titleColor = color(theme.colors.text)
@@ -127,21 +156,7 @@ class ListItem extends React.Component<Props> {
             >
               {title}
             </Text>
-            {description ? (
-              <Text
-                ellipsizeMode={descriptionEllipsizeMode}
-                numberOfLines={2}
-                style={[
-                  styles.description,
-                  {
-                    color: descriptionColor,
-                  },
-                  descriptionStyle,
-                ]}
-              >
-                {description}
-              </Text>
-            ) : null}
+            {this.renderDescription(description, descriptionColor)}
           </View>
           {right ? right({ color: descriptionColor }) : null}
         </View>
diff --git a/src/types.js b/src/types.js
index e35b15703..ea757180e 100644
--- a/src/types.js
+++ b/src/types.js
@@ -35,3 +35,5 @@ export type $RemoveChildren<T> = $Diff<
   React.ElementConfig<T>,
   { children: any }
 >;
+
+export type EllipsizeProp = 'head' | 'middle' | 'tail' | 'clip';
diff --git a/typings/components/List.d.ts b/typings/components/List.d.ts
index 3b9ca371c..463933ae4 100644
--- a/typings/components/List.d.ts
+++ b/typings/components/List.d.ts
@@ -6,7 +6,7 @@ import {
   TextProps,
   TextStyle,
 } from 'react-native';
-import { ThemeShape, IconSource } from '../types';
+import { ThemeShape, IconSource, EllipsizeProp } from '../types';
 import { TouchableRipplePropsWithoutChildren } from './TouchableRipple';
 
 export interface AccordionProps {
@@ -39,8 +39,8 @@ export interface ItemProps extends TouchableRipplePropsWithoutChildren {
   right?: (props: { color: string }) => React.ReactNode;
   titleStyle?: StyleProp<TextStyle>;
   descriptionStyle?: StyleProp<TextStyle>;
-  titleEllipsizeMode?: 'head' | 'middle' | 'tail' | 'clip';
-  descriptionEllipsizeMode?: 'head' | 'middle' | 'tail' | 'clip';
+  titleEllipsizeMode?: EllipsizeProp;
+  descriptionEllipsizeMode?: EllipsizeProp;
 }
 
 export declare class Item extends React.Component<ItemProps> {}
diff --git a/typings/types.d.ts b/typings/types.d.ts
index d9e93790c..5b0aca554 100644
--- a/typings/types.d.ts
+++ b/typings/types.d.ts
@@ -50,3 +50,5 @@ export declare class Provider extends React.Component<{
   children: React.ReactNode;
   theme?: ThemeShape;
 }> {}
+
+export type EllipsizeProp = 'head' | 'middle' | 'tail' | 'clip';


Test patch:
diff --git a/src/components/__tests__/ListItem.test.js b/src/components/__tests__/ListItem.test.js
index 3fd172b17..5be212dec 100644
--- a/src/components/__tests__/ListItem.test.js
+++ b/src/components/__tests__/ListItem.test.js
@@ -2,9 +2,10 @@
 
 import * as React from 'react';
 import renderer from 'react-test-renderer';
-import { Text } from 'react-native';
+import { Text, View } from 'react-native';
 import ListItem from '../List/ListItem';
 import ListIcon from '../List/ListIcon';
+import Chip from '../Chip';
 
 it('renders list item with title and description', () => {
   const tree = renderer
@@ -66,3 +67,32 @@ it('renders list item with custom title and description styles', () => {
 
   expect(tree).toMatchSnapshot();
 });
+
+it('renders list item with custom description', () => {
+  const tree = renderer
+    .create(
+      <ListItem
+        title="List Item with custom description"
+        description={({ ellipsizeMode, color: descriptionColor, fontSize }) => (
+          <View>
+            <Text
+              numberOfLines={2}
+              ellipsizeMode={ellipsizeMode}
+              style={{ color: descriptionColor, fontSize }}
+            >
+              React Native Paper is a high-quality, standard-compliant Design
+              Design library that has you covered in all major use-cases.
+            </Text>
+            <View>
+              <Chip icon="picture-as-pdf" onPress={() => {}}>
+                DOCS.pdf
+              </Chip>
+            </View>
+          </View>
+        )}
+      />
+    )
+    .toJSON();
+
+  expect(tree).toMatchSnapshot();
+});
diff --git a/src/components/__tests__/__snapshots__/ListItem.test.js.snap b/src/components/__tests__/__snapshots__/ListItem.test.js.snap
index f1c52d538..6314b67ca 100644
--- a/src/components/__tests__/__snapshots__/ListItem.test.js.snap
+++ b/src/components/__tests__/__snapshots__/ListItem.test.js.snap
@@ -1,5 +1,212 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
+exports[`renders list item with custom description 1`] = `
+<View
+  accessible={true}
+  isTVSelectable={true}
+  onResponderGrant={[Function]}
+  onResponderMove={[Function]}
+  onResponderRelease={[Function]}
+  onResponderTerminate={[Function]}
+  onResponderTerminationRequest={[Function]}
+  onStartShouldSetResponder={[Function]}
+  style={
+    Array [
+      false,
+      Array [
+        Object {
+          "padding": 8,
+        },
+        undefined,
+      ],
+    ]
+  }
+>
+  <View
+    style={
+      Object {
+        "flexDirection": "row",
+      }
+    }
+  >
+    <View
+      pointerEvents="none"
+      style={
+        Array [
+          Object {
+            "margin": 8,
+          },
+          Object {
+            "flex": 1,
+            "justifyContent": "center",
+          },
+        ]
+      }
+    >
+      <Text
+        numberOfLines={1}
+        style={
+          Array [
+            Object {
+              "color": "#000000",
+              "fontFamily": "Helvetica Neue",
+              "textAlign": "left",
+              "writingDirection": "ltr",
+            },
+            Array [
+              Object {
+                "fontSize": 16,
+              },
+              Object {
+                "color": "rgba(0, 0, 0, 0.87)",
+              },
+              undefined,
+            ],
+          ]
+        }
+      >
+        List Item with custom description
+      </Text>
+      <View>
+        <Text
+          numberOfLines={2}
+          style={
+            Object {
+              "color": "rgba(0, 0, 0, 0.54)",
+              "fontSize": 14,
+            }
+          }
+        >
+          React Native Paper is a high-quality, standard-compliant Design Design library that has you covered in all major use-cases.
+        </Text>
+        <View>
+          <View
+            style={
+              Object {
+                "backgroundColor": "#ebebeb",
+                "borderColor": "#ebebeb",
+                "borderRadius": 16,
+                "borderStyle": "solid",
+                "borderWidth": 0.5,
+                "elevation": 0,
+              }
+            }
+          >
+            <View
+              accessibilityRole="button"
+              accessibilityStates={Array []}
+              accessible={true}
+              isTVSelectable={true}
+              onResponderGrant={[Function]}
+              onResponderMove={[Function]}
+              onResponderRelease={[Function]}
+              onResponderTerminate={[Function]}
+              onResponderTerminationRequest={[Function]}
+              onStartShouldSetResponder={[Function]}
+              style={
+                Array [
+                  Object {
+                    "overflow": "hidden",
+                  },
+                  Object {
+                    "borderRadius": 16,
+                  },
+                ]
+              }
+            >
+              <View
+                style={
+                  Object {
+                    "alignItems": "center",
+                    "flexDirection": "row",
+                    "paddingHorizontal": 4,
+                  }
+                }
+              >
+                <View
+                  style={
+                    Array [
+                      Object {
+                        "padding": 4,
+                      },
+                      null,
+                    ]
+                  }
+                >
+                  <Text
+                    accessibilityElementsHidden={true}
+                    allowFontScaling={false}
+                    importantForAccessibility="no-hide-descendants"
+                    pointerEvents="none"
+                    style={
+                      Array [
+                        Object {
+                          "color": "rgba(0, 0, 0, 0.54)",
+                          "fontSize": 18,
+                        },
+                        Array [
+                          Object {
+                            "transform": Array [
+                              Object {
+                                "scaleX": 1,
+                              },
+                            ],
+                          },
+                          Object {
+                            "backgroundColor": "transparent",
+                          },
+                        ],
+                        Object {
+                          "fontFamily": "Material Icons",
+                          "fontStyle": "normal",
+                          "fontWeight": "normal",
+                        },
+                        Object {},
+                      ]
+                    }
+                  >
+                    
+                  </Text>
+                </View>
+                <Text
+                  numberOfLines={1}
+                  style={
+                    Array [
+                      Object {
+                        "color": "#000000",
+                        "fontFamily": "Helvetica Neue",
+                        "textAlign": "left",
+                        "writingDirection": "ltr",
+                      },
+                      Array [
+                        Object {
+                          "lineHeight": 24,
+                          "marginVertical": 4,
+                          "minHeight": 24,
+                          "textAlignVertical": "center",
+                        },
+                        Object {
+                          "color": "rgba(0, 0, 0, 0.87)",
+                          "marginLeft": 4,
+                          "marginRight": 8,
+                        },
+                        undefined,
+                      ],
+                    ]
+                  }
+                >
+                  DOCS.pdf
+                </Text>
+              </View>
+            </View>
+          </View>
+        </View>
+      </View>
+    </View>
+  </View>
+</View>
+`;
+
 exports[`renders list item with custom title and description styles 1`] = `
 <View
   accessible={true}