@shoutem/ui 4.6.6-rc.1 → 4.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +1 -2
  3. package/components/ActionSheet/ActionSheet.js +6 -6
  4. package/components/DateTimePicker.js +2 -2
  5. package/components/DropDownMenu/DropDownMenu.js +1 -1
  6. package/components/DropDownMenu/DropDownModal.js +2 -2
  7. package/components/EmptyListImage.js +9 -5
  8. package/components/FormGroup.js +0 -1
  9. package/components/GridRow.js +2 -2
  10. package/components/HorizontalPager/HorizontalPager.js +2 -2
  11. package/components/Icon/services/icons.js +0 -2
  12. package/components/Icon/services/index.js +1 -1
  13. package/components/Image.js +1 -1
  14. package/components/ImageBackground.js +1 -1
  15. package/components/ImageGallery/ImageGallery.android.js +1 -0
  16. package/components/ImageGallery/ImageGallery.ios.js +2 -1
  17. package/components/ImageGalleryOverlay.js +1 -1
  18. package/components/ImagePreview.js +2 -2
  19. package/components/InlineDropDownMenu/InlineDropDownMenu.js +24 -27
  20. package/components/InlineDropDownMenu/InlineDropDownMenuItem.js +13 -14
  21. package/components/ListView.js +71 -32
  22. package/components/LoadingIndicator.js +1 -1
  23. package/components/NavigationBar/NavigationBar.js +3 -7
  24. package/components/NavigationBar/NavigationBarAnimations.js +1 -1
  25. package/components/ScrollView/ScrollDriverProvider.js +23 -3
  26. package/components/ScrollView/ScrollView.js +10 -8
  27. package/components/ShareButton.js +1 -1
  28. package/components/Spinner.js +1 -1
  29. package/components/Switch.js +2 -2
  30. package/components/TabMenu/TabMenu.js +2 -2
  31. package/components/TabMenu/TabMenuItem.js +7 -4
  32. package/components/Text.js +2 -2
  33. package/components/TextInput.js +2 -2
  34. package/components/Tile.js +1 -1
  35. package/components/Touchable.js +2 -2
  36. package/components/TouchableNativeFeedback.js +2 -2
  37. package/components/TouchableOpacity.js +1 -1
  38. package/components/Video/Video.js +1 -1
  39. package/components/Video/VideoSourceReader.js +2 -1
  40. package/components/View.js +1 -1
  41. package/components/YearRangePicker/YearRangePicker.js +10 -4
  42. package/components/YearRangePicker/YearRangePickerButton.js +27 -39
  43. package/components/YearRangePicker/YearRangePickerModal.js +68 -38
  44. package/examples/components/Cards.js +1 -1
  45. package/examples/components/DropDownMenus.js +8 -8
  46. package/examples/components/Examples.js +1 -1
  47. package/examples/components/FormComponents.js +1 -1
  48. package/examples/components/Headers.js +1 -1
  49. package/examples/components/NavigationBars.js +4 -4
  50. package/examples/components/Rows.js +1 -1
  51. package/examples/components/Stage.js +1 -1
  52. package/examples/components/Tiles.js +1 -1
  53. package/examples/components/Typography.js +1 -1
  54. package/examples/components/Videos.js +3 -3
  55. package/helpers/device-selector.js +11 -3
  56. package/helpers/keyboard.js +2 -3
  57. package/html/Html.js +3 -3
  58. package/html/components/Image.js +1 -1
  59. package/html/components/SimpleHtml.js +9 -9
  60. package/html/elements/A.js +3 -3
  61. package/html/elements/Block.js +2 -2
  62. package/html/elements/Img.js +1 -1
  63. package/html/elements/Inline.js +5 -5
  64. package/html/elements/Text.js +2 -2
  65. package/html/elements/list/Ol.js +1 -1
  66. package/html/elements/list/Ul.js +1 -1
  67. package/html/elements/list/index.js +4 -4
  68. package/html/index.js +33 -33
  69. package/html/services/ElementRegistry.js +1 -1
  70. package/html/services/HtmlParser.js +2 -1
  71. package/package.json +40 -30
  72. package/scripts/add-native-deps.js +0 -1
  73. package/theme.js +10 -12
package/LICENSE CHANGED
@@ -27,4 +27,4 @@ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
27
27
  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
28
28
  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29
29
  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30
- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package/README.md CHANGED
@@ -70,7 +70,6 @@ To see other components, just import them from `@shoutem/ui` and render them.
70
70
 
71
71
  You can also use standard React Native components in your layouts anywhere you want, but they will not inherit either the theme or the parent styles, so you will need to style them manually.
72
72
 
73
-
74
73
  ### Restaurants app
75
74
 
76
75
  Clone the [Shoutem UI](https://github.com/shoutem/ui) repository:
@@ -107,7 +106,7 @@ It consists of three libraries:
107
106
 
108
107
  - [@shoutem/ui](https://github.com/shoutem/ui): beautiful and customizable UI components
109
108
  - [@shoutem/theme](https://github.com/shoutem/theme): “CSS-way” of styling entire app
110
- - [@shoutem/animation](https://github.com/shoutem/animation): declarative way of applying ready-made animations
109
+ - [@shoutem/animation](https://github.com/shoutem/animation): declarative way of applying ready-made animations
111
110
 
112
111
  ## License
113
112
 
@@ -1,8 +1,8 @@
1
1
  import React, { PureComponent } from 'react';
2
- import PropTypes from 'prop-types';
2
+ import { Animated, Dimensions, TouchableOpacity } from 'react-native';
3
3
  import autoBindReact from 'auto-bind/react';
4
- import { Animated, TouchableOpacity, Dimensions } from 'react-native';
5
4
  import _ from 'lodash';
5
+ import PropTypes from 'prop-types';
6
6
  import { connectStyle } from '@shoutem/theme';
7
7
  import { IPHONE_X_HOME_INDICATOR_PADDING } from '../../const';
8
8
  import { Device } from '../../helpers';
@@ -84,11 +84,11 @@ class ActionSheet extends PureComponent {
84
84
  Animated.parallel([
85
85
  Animated.spring(yPos, {
86
86
  toValue,
87
- useNativeDriver: true
87
+ useNativeDriver: true,
88
88
  }),
89
89
  Animated.timing(opacity, {
90
90
  toValue,
91
- useNativeDriver: false
91
+ useNativeDriver: false,
92
92
  }),
93
93
  ]).start();
94
94
  }
@@ -101,13 +101,13 @@ class ActionSheet extends PureComponent {
101
101
  Animated.parallel([
102
102
  Animated.spring(yPos, {
103
103
  toValue,
104
- useNativeDriver: true
104
+ useNativeDriver: true,
105
105
  }),
106
106
  Animated.timing(opacity, {
107
107
  toValue,
108
108
  delay: 100,
109
109
  duration: 150,
110
- useNativeDriver: false
110
+ useNativeDriver: false,
111
111
  }),
112
112
  ]).start(this.hideComponent);
113
113
  }
@@ -1,9 +1,9 @@
1
1
  import React, { PureComponent } from 'react';
2
+ import { Platform } from 'react-native';
3
+ import Modal from 'react-native-modal';
2
4
  import RNCDateTimePicker from '@react-native-community/datetimepicker';
3
5
  import autoBindReact from 'auto-bind/react';
4
6
  import PropTypes from 'prop-types';
5
- import { Platform } from 'react-native';
6
- import Modal from 'react-native-modal';
7
7
  import { connectStyle } from '@shoutem/theme';
8
8
  import { Button } from './Button';
9
9
  import { Icon } from './Icon';
@@ -1,7 +1,7 @@
1
1
  import React, { PureComponent } from 'react';
2
2
  import autoBindReact from 'auto-bind/react';
3
- import PropTypes from 'prop-types';
4
3
  import _ from 'lodash';
4
+ import PropTypes from 'prop-types';
5
5
  import { connectStyle } from '@shoutem/theme';
6
6
  import { Button } from '../Button';
7
7
  import { Icon } from '../Icon';
@@ -1,9 +1,9 @@
1
1
  import React, { PureComponent } from 'react';
2
+ import { Dimensions, Modal } from 'react-native';
2
3
  import autoBindReact from 'auto-bind/react';
3
4
  import _ from 'lodash';
4
5
  import PropTypes from 'prop-types';
5
- import { Modal, Dimensions } from 'react-native';
6
- import { connectStyle, changeColorAlpha } from '@shoutem/theme';
6
+ import { changeColorAlpha, connectStyle } from '@shoutem/theme';
7
7
  import { Button } from '../Button';
8
8
  import { Icon } from '../Icon';
9
9
  import { LinearGradient } from '../LinearGradient';
@@ -7,11 +7,6 @@ import { Text, Title, View } from '@shoutem/ui';
7
7
  import EmptyList from '../assets/images/emptyList.svg';
8
8
 
9
9
  class EmptyListImage extends PureComponent {
10
- static defaultProps = {
11
- title: "It's empty in here",
12
- message: "We couldn't find anything to show...",
13
- };
14
-
15
10
  constructor(props) {
16
11
  super(props);
17
12
 
@@ -66,6 +61,15 @@ EmptyListImage.propTypes = {
66
61
  titleStyle: PropTypes.object,
67
62
  };
68
63
 
64
+ EmptyListImage.defaultProps = {
65
+ image: undefined,
66
+ imageStyle: undefined,
67
+ message: "We couldn't find anything to show...",
68
+ messageStyle: undefined,
69
+ title: "It's empty in here",
70
+ titleStyle: undefined,
71
+ };
72
+
69
73
  const StyledView = connectStyle('shoutem.ui.EmptyListImage')(EmptyListImage);
70
74
 
71
75
  export { StyledView as EmptyListImage };
@@ -1,7 +1,6 @@
1
1
  import React, { PureComponent } from 'react';
2
2
  import { connectAnimation } from '@shoutem/animation';
3
3
  import { connectStyle } from '@shoutem/theme';
4
-
5
4
  import { View } from './View';
6
5
 
7
6
  class FormGroup extends PureComponent {
@@ -1,7 +1,7 @@
1
- import React, { PureComponent, Children } from 'react';
1
+ import React, { Children, PureComponent } from 'react';
2
+ import { View as RNView, ViewPropTypes } from 'react-native';
2
3
  import _ from 'lodash';
3
4
  import PropTypes from 'prop-types';
4
- import { View as RNView, ViewPropTypes } from 'react-native';
5
5
  import { connectAnimation } from '@shoutem/animation';
6
6
  import { connectStyle } from '@shoutem/theme';
7
7
  import { View } from './View';
@@ -1,8 +1,8 @@
1
1
  import React, { PureComponent } from 'react';
2
+ import { InteractionManager, LayoutAnimation, ScrollView } from 'react-native';
2
3
  import autoBindReact from 'auto-bind/react';
3
4
  import _ from 'lodash';
4
5
  import PropTypes from 'prop-types';
5
- import { InteractionManager, LayoutAnimation, ScrollView } from 'react-native';
6
6
  import { connectStyle } from '@shoutem/theme';
7
7
  import { View } from '../View';
8
8
  import { Page } from './Page';
@@ -118,7 +118,7 @@ class HorizontalPager extends PureComponent {
118
118
  const { selectedIndex } = this.state;
119
119
  const { onIndexSelected } = this.props;
120
120
 
121
- const contentOffset = event.nativeEvent.contentOffset;
121
+ const { contentOffset } = event.nativeEvent;
122
122
  const newSelectedIndex = this.calculateIndex(contentOffset);
123
123
 
124
124
  if (selectedIndex === newSelectedIndex) {
@@ -60,8 +60,6 @@ export function registerIcons(config) {
60
60
  } else {
61
61
  addNewIcon(config);
62
62
  }
63
-
64
- return;
65
63
  }
66
64
 
67
65
  registerIcons(defaultConfig);
@@ -1 +1 @@
1
- export { registerIcons, getIcon } from './icons';
1
+ export { getIcon, registerIcons } from './icons';
@@ -1,7 +1,7 @@
1
1
  import React, { PureComponent } from 'react';
2
+ import { Image as RNImage, Platform } from 'react-native';
2
3
  import autoBindReact from 'auto-bind/react';
3
4
  import _ from 'lodash';
4
- import { Image as RNImage, Platform } from 'react-native';
5
5
  import { connectAnimation } from '@shoutem/animation';
6
6
  import { connectStyle } from '@shoutem/theme';
7
7
 
@@ -1,7 +1,7 @@
1
1
  import React, { PureComponent } from 'react';
2
+ import { ImageBackground as RNImageBackground, Platform } from 'react-native';
2
3
  import autoBindReact from 'auto-bind/react';
3
4
  import _ from 'lodash';
4
- import { ImageBackground as RNImageBackground, Platform } from 'react-native';
5
5
  import { connectAnimation } from '@shoutem/animation';
6
6
  import { connectStyle } from '@shoutem/theme';
7
7
 
@@ -5,6 +5,7 @@ import { ImageGalleryBase } from './ImageGalleryBase';
5
5
 
6
6
  class ImageGallery extends ImageGalleryBase {
7
7
  static IMAGE_PREVIEW_MODE = ImageGalleryBase.IMAGE_PREVIEW_MODE;
8
+
8
9
  static IMAGE_GALLERY_MODE = ImageGalleryBase.IMAGE_GALLERY_MODE;
9
10
 
10
11
  renderImage(imageProps, imageData, imageIndex) {
@@ -1,12 +1,13 @@
1
1
  import React from 'react';
2
- import autoBindReact from 'auto-bind/react';
3
2
  import { InteractionManager } from 'react-native';
4
3
  import TransformableImage from 'react-native-transformable-image';
4
+ import autoBindReact from 'auto-bind/react';
5
5
  import { connectStyle } from '@shoutem/theme';
6
6
  import { ImageGalleryBase } from './ImageGalleryBase';
7
7
 
8
8
  class ImageGallery extends ImageGalleryBase {
9
9
  static IMAGE_PREVIEW_MODE = ImageGalleryBase.IMAGE_PREVIEW_MODE;
10
+
10
11
  static IMAGE_GALLERY_MODE = ImageGalleryBase.IMAGE_GALLERY_MODE;
11
12
 
12
13
  constructor(props) {
@@ -1,7 +1,7 @@
1
1
  import React, { PureComponent } from 'react';
2
+ import { ScrollView } from 'react-native';
2
3
  import autoBindReact from 'auto-bind/react';
3
4
  import PropTypes from 'prop-types';
4
- import { ScrollView } from 'react-native';
5
5
  import { connectAnimation } from '@shoutem/animation';
6
6
  import { connectStyle } from '@shoutem/theme';
7
7
  import { Icon } from './Icon';
@@ -1,8 +1,8 @@
1
1
  import React, { PureComponent } from 'react';
2
+ import { Image, Modal, TouchableOpacity, View } from 'react-native';
3
+ import Icon from 'react-native-vector-icons/MaterialIcons';
2
4
  import autoBindReact from 'auto-bind/react';
3
5
  import PropTypes from 'prop-types';
4
- import { View, Modal, Image, TouchableOpacity } from 'react-native';
5
- import Icon from 'react-native-vector-icons/MaterialIcons';
6
6
  import { makeZoomable } from '@shoutem/animation';
7
7
  import { connectStyle } from '@shoutem/theme';
8
8
 
@@ -1,13 +1,13 @@
1
1
  import React, { PureComponent } from 'react';
2
+ import { Animated, FlatList } from 'react-native';
2
3
  import autoBindReact from 'auto-bind/react';
3
- import { FlatList, Animated } from 'react-native';
4
4
  import _ from 'lodash';
5
5
  import PropTypes from 'prop-types';
6
6
  import { connectStyle } from '@shoutem/theme';
7
+ import { Icon } from '../Icon';
8
+ import { Caption, Text } from '../Text';
7
9
  import { TouchableOpacity } from '../TouchableOpacity';
8
10
  import { View } from '../View';
9
- import { Caption, Text } from '../Text';
10
- import { Icon } from '../Icon';
11
11
  import { InlineDropDownMenuItem } from './InlineDropDownMenuItem';
12
12
 
13
13
  const AnimatedIcon = Animated.createAnimatedComponent(Icon);
@@ -43,16 +43,13 @@ class InlineDropDownMenu extends PureComponent {
43
43
 
44
44
  const toValue = collapsed ? 0 : 1;
45
45
 
46
- this.setState(
47
- { collapsed: !collapsed },
48
- () => Animated.timing(
49
- this.dropDownIconValue,
50
- {
51
- toValue,
52
- useNativeDriver: true,
53
- duration: 300,
54
- }
55
- ).start());
46
+ this.setState({ collapsed: !collapsed }, () =>
47
+ Animated.timing(this.dropDownIconValue, {
48
+ toValue,
49
+ useNativeDriver: true,
50
+ duration: 300,
51
+ }).start(),
52
+ );
56
53
  }
57
54
 
58
55
  handleOptionPress(option) {
@@ -78,21 +75,19 @@ class InlineDropDownMenu extends PureComponent {
78
75
  selectedDescriptor={selectedDescriptor}
79
76
  onItemPressed={this.handleOptionPress}
80
77
  />
81
- )
78
+ );
82
79
  }
83
80
 
84
81
  render() {
85
- const {
86
- style,
87
- heading,
88
- selectedOption,
89
- options,
90
- } = this.props;
82
+ const { style, heading, selectedOption, options } = this.props;
91
83
  const { collapsed } = this.state;
92
84
 
93
85
  return (
94
86
  <View>
95
- <TouchableOpacity style={style.container} onPress={this.handleToggleMenuPress}>
87
+ <TouchableOpacity
88
+ style={style.container}
89
+ onPress={this.handleToggleMenuPress}
90
+ >
96
91
  <Caption styleName="muted md-gutter-bottom">{heading}</Caption>
97
92
  <View styleName="space-between horizontal v-center">
98
93
  <Text>{selectedOption?.title}</Text>
@@ -101,12 +96,14 @@ class InlineDropDownMenu extends PureComponent {
101
96
  styleName="md-gutter-left"
102
97
  style={{
103
98
  ...style.icon,
104
- transform: [{
105
- rotate: this.dropDownIconValue.interpolate({
106
- inputRange: [0, 1],
107
- outputRange: ['0deg', '180deg']
108
- })
109
- }]
99
+ transform: [
100
+ {
101
+ rotate: this.dropDownIconValue.interpolate({
102
+ inputRange: [0, 1],
103
+ outputRange: ['0deg', '180deg'],
104
+ }),
105
+ },
106
+ ],
110
107
  }}
111
108
  />
112
109
  </View>
@@ -1,11 +1,11 @@
1
1
  import React, { PureComponent } from 'react';
2
- import autoBindReact from 'auto-bind/react';
3
2
  import { Animated, Dimensions } from 'react-native';
3
+ import autoBindReact from 'auto-bind/react';
4
4
  import _ from 'lodash';
5
5
  import PropTypes from 'prop-types';
6
6
  import { connectStyle } from '@shoutem/theme';
7
- import { TouchableOpacity } from '../TouchableOpacity';
8
7
  import { Text } from '../Text';
8
+ import { TouchableOpacity } from '../TouchableOpacity';
9
9
 
10
10
  const window = Dimensions.get('window');
11
11
  const AnimatedTouchable = Animated.createAnimatedComponent(TouchableOpacity);
@@ -30,14 +30,11 @@ class InlineDropDownMenuItem extends PureComponent {
30
30
  componentDidMount() {
31
31
  const { index } = this.props;
32
32
 
33
- Animated.timing(
34
- this.animatedValue,
35
- {
36
- toValue: 1,
37
- useNativeDriver: true,
38
- duration: 300 + index * 15,
39
- }
40
- ).start();
33
+ Animated.timing(this.animatedValue, {
34
+ toValue: 1,
35
+ useNativeDriver: true,
36
+ duration: 300 + index * 15,
37
+ }).start();
41
38
  }
42
39
 
43
40
  handlePress() {
@@ -51,7 +48,9 @@ class InlineDropDownMenuItem extends PureComponent {
51
48
  render() {
52
49
  const { isSelected, selectedDescriptor, item, style } = this.props;
53
50
 
54
- const resolvedText = isSelected ? `${item.title} (${selectedDescriptor})` : item.title;
51
+ const resolvedText = isSelected
52
+ ? `${item.title} (${selectedDescriptor})`
53
+ : item.title;
55
54
  const textStyle = isSelected ? 'muted' : '';
56
55
 
57
56
  return (
@@ -64,10 +63,10 @@ class InlineDropDownMenuItem extends PureComponent {
64
63
  translateX: this.animatedValue.interpolate({
65
64
  inputRange: [0, 1],
66
65
  outputRange: [window.width, 0],
67
- })
68
- }
66
+ }),
67
+ },
69
68
  ],
70
- }
69
+ },
71
70
  ]}
72
71
  disabled={isSelected}
73
72
  onPress={this.handlePress}
@@ -1,15 +1,15 @@
1
1
  import React, { PureComponent } from 'react';
2
- import autoBindReact from 'auto-bind/react';
3
- import _ from 'lodash';
4
- import PropTypes from 'prop-types';
5
2
  import {
6
- View,
7
3
  FlatList,
8
- SectionList,
4
+ Platform,
9
5
  RefreshControl,
6
+ SectionList,
10
7
  StatusBar,
11
- Platform,
8
+ View,
12
9
  } from 'react-native';
10
+ import autoBindReact from 'auto-bind/react';
11
+ import _ from 'lodash';
12
+ import PropTypes from 'prop-types';
13
13
  import { connectStyle } from '@shoutem/theme';
14
14
  import { Divider } from './Divider';
15
15
  import { EmptyListImage } from './EmptyListImage';
@@ -34,26 +34,6 @@ function renderDefaultSectionHeader(section) {
34
34
  }
35
35
 
36
36
  class ListView extends PureComponent {
37
- static propTypes = {
38
- autoHideHeader: PropTypes.bool,
39
- style: PropTypes.object,
40
- contentContainerStyle: PropTypes.object,
41
- data: PropTypes.array,
42
- loading: PropTypes.bool,
43
- onLoadMore: PropTypes.func,
44
- onLoadMoreThreshold: PropTypes.number,
45
- onRefresh: PropTypes.func,
46
- getSectionId: PropTypes.func,
47
- sections: PropTypes.array,
48
- renderRow: PropTypes.func,
49
- renderHeader: PropTypes.func,
50
- renderFooter: PropTypes.func,
51
- renderSectionHeader: PropTypes.func,
52
- scrollDriver: PropTypes.object,
53
- hasFeaturedItem: PropTypes.bool,
54
- renderFeaturedItem: PropTypes.func,
55
- };
56
-
57
37
  static getDerivedStateFromProps(props, state) {
58
38
  const isLoading = props.loading;
59
39
 
@@ -131,7 +111,7 @@ class ListView extends PureComponent {
131
111
 
132
112
  // configuration
133
113
  // default load more threshold
134
- mappedProps.onEndReachedThreshold = onLoadMoreThreshold || 0.5;
114
+ mappedProps.onEndReachedThreshold = onLoadMoreThreshold;
135
115
 
136
116
  // style
137
117
  mappedProps.style = style.list;
@@ -313,17 +293,21 @@ class ListView extends PureComponent {
313
293
  }
314
294
 
315
295
  renderListEmptyComponent() {
316
- const { ListEmptyComponent, loading } = this.props;
296
+ const { loading } = this.props;
317
297
 
318
298
  if (loading) {
319
299
  return null;
320
300
  }
321
301
 
302
+ const { ListEmptyComponent } = this.props;
303
+
322
304
  if (ListEmptyComponent) {
323
305
  return <ListEmptyComponent />;
324
306
  }
325
307
 
326
- return <EmptyListImage />;
308
+ const { emptyListMessage, emptyListTitle } = this.props;
309
+
310
+ return <EmptyListImage message={emptyListMessage} title={emptyListTitle} />;
327
311
  }
328
312
 
329
313
  renderRefreshControl() {
@@ -346,20 +330,27 @@ class ListView extends PureComponent {
346
330
 
347
331
  render() {
348
332
  const {
333
+ emptyListMessage,
334
+ emptyListTitle,
349
335
  sections,
350
336
  hasFeaturedItem,
351
337
  ListEmptyComponent,
352
338
  loading,
353
339
  } = this.props;
354
340
 
355
- /* ListEmptyComponent in SectionList is handled differently due to the known issue with empty data interpretation.
356
- https://github.com/facebook/react-native/issues/14721 */
341
+ // ListEmptyComponent in SectionList is handled differently due to the known
342
+ // issue with empty data interpretation.
343
+ // https://github.com/facebook/react-native/issues/14721
357
344
  if (
358
345
  sections &&
359
346
  _.every(sections, section => _.isEmpty(section.data)) &&
360
347
  !loading
361
348
  ) {
362
- return ListEmptyComponent ? <ListEmptyComponent /> : <EmptyListImage />;
349
+ return ListEmptyComponent ? (
350
+ <ListEmptyComponent />
351
+ ) : (
352
+ <EmptyListImage message={emptyListMessage} title={emptyListTitle} />
353
+ );
363
354
  }
364
355
 
365
356
  if (sections || hasFeaturedItem) {
@@ -370,6 +361,54 @@ class ListView extends PureComponent {
370
361
  }
371
362
  }
372
363
 
364
+ ListView.propTypes = {
365
+ autoHideHeader: PropTypes.bool,
366
+ contentContainerStyle: PropTypes.object,
367
+ data: PropTypes.array,
368
+ emptyListMessage: PropTypes.string,
369
+ emptyListTitle: PropTypes.string,
370
+ getSectionId: PropTypes.func,
371
+ hasFeaturedItem: PropTypes.bool,
372
+ keyExtractor: PropTypes.func,
373
+ ListEmptyComponent: PropTypes.node,
374
+ loading: PropTypes.bool,
375
+ renderFeaturedItem: PropTypes.func,
376
+ renderFooter: PropTypes.func,
377
+ renderHeader: PropTypes.func,
378
+ renderRow: PropTypes.func,
379
+ renderSectionHeader: PropTypes.func,
380
+ scrollDriver: PropTypes.object,
381
+ sections: PropTypes.array,
382
+ style: PropTypes.object,
383
+ onLoadMore: PropTypes.func,
384
+ onLoadMoreThreshold: PropTypes.number,
385
+ onRefresh: PropTypes.func,
386
+ };
387
+
388
+ ListView.defaultProps = {
389
+ autoHideHeader: false,
390
+ contentContainerStyle: {},
391
+ data: undefined,
392
+ emptyListMessage: undefined,
393
+ emptyListTitle: undefined,
394
+ getSectionId: undefined,
395
+ hasFeaturedItem: false,
396
+ keyExtractor: undefined,
397
+ ListEmptyComponent: undefined,
398
+ loading: false,
399
+ renderFeaturedItem: undefined,
400
+ renderFooter: undefined,
401
+ renderHeader: undefined,
402
+ renderRow: undefined,
403
+ renderSectionHeader: undefined,
404
+ scrollDriver: undefined,
405
+ sections: undefined,
406
+ style: {},
407
+ onLoadMore: undefined,
408
+ onLoadMoreThreshold: 0.5,
409
+ onRefresh: undefined,
410
+ };
411
+
373
412
  const StyledListView = connectStyle('shoutem.ui.ListView', {
374
413
  listContent: {
375
414
  paddingBottom: 5,
@@ -1,7 +1,7 @@
1
1
  import React, { PureComponent } from 'react';
2
2
  import { connectStyle } from '@shoutem/theme';
3
- import { View } from './View';
4
3
  import { Spinner } from './Spinner';
4
+ import { View } from './View';
5
5
 
6
6
  /**
7
7
  * Renders a loading indicator (spinner) that fits into available space (container)
@@ -1,14 +1,10 @@
1
1
  import React, { PureComponent } from 'react';
2
- import PropTypes from 'prop-types';
3
- import { StatusBar, Animated, Platform, View } from 'react-native';
4
-
2
+ import { Animated, Platform, StatusBar, View } from 'react-native';
5
3
  import _ from 'lodash';
6
-
4
+ import PropTypes from 'prop-types';
7
5
  import color from 'tinycolor2';
8
-
9
- import { connectStyle } from '@shoutem/theme';
10
6
  import { connectAnimation } from '@shoutem/animation';
11
-
7
+ import { connectStyle } from '@shoutem/theme';
12
8
  import { Device } from '../../helpers';
13
9
  import composeChildren from './composeChildren';
14
10
 
@@ -21,7 +21,7 @@ class ColorAnimation {
21
21
  clearToStandard(atAnimatedValue) {
22
22
  const defaultAnimatedValue = atAnimatedValue || 150;
23
23
  const standardTextColor = this.textColor || 'rgba(0,0,0,1)';
24
- const animatedValue = this.animatedValue;
24
+ const { animatedValue } = this;
25
25
  return {
26
26
  color: animatedValue.interpolate({
27
27
  inputRange: [0, defaultAnimatedValue],
@@ -1,4 +1,4 @@
1
- import { PureComponent, Children } from 'react';
1
+ import { Children, PureComponent } from 'react';
2
2
  import _ from 'lodash';
3
3
  import PropTypes from 'prop-types';
4
4
  import { DriverShape, ScrollDriver } from '@shoutem/animation';
@@ -22,6 +22,11 @@ export class ScrollDriverProvider extends PureComponent {
22
22
  static propTypes = {
23
23
  children: PropTypes.node,
24
24
  driver: DriverShape,
25
+ // Used to propagate animation driver changes to components who aren't
26
+ // children of ScrollDriver, recieves driver as argument.
27
+ // TODO: Rewrite for new context API.
28
+ onAnimationDriverChange: PropTypes.func,
29
+ onScroll: PropTypes.func,
25
30
  };
26
31
 
27
32
  constructor(props, context) {
@@ -42,19 +47,34 @@ export class ScrollDriverProvider extends PureComponent {
42
47
  }
43
48
 
44
49
  setupAnimationDriver(props, context) {
50
+ const { onAnimationDriverChange } = this.props;
51
+
45
52
  if (props.driver) {
46
53
  this.animationDriver = props.driver;
47
54
  } else if (context.driverProvider) {
48
55
  this.animationDriver = context.animationDriver;
49
56
  } else if (!this.animationDriver) {
50
- this.animationDriver = new ScrollDriver({ useNativeDriver: true });
57
+ this.animationDriver = new ScrollDriver(
58
+ { useNativeDriver: true, nativeScrollEventThrottle: 20 },
59
+ props.onScroll,
60
+ );
61
+ }
62
+
63
+ if (onAnimationDriverChange) {
64
+ onAnimationDriverChange(this.animationDriver);
51
65
  }
52
66
  }
53
67
 
54
68
  setAnimationDriver(driver, primaryScrollView) {
55
69
  if (driver || !this.animationDriver || primaryScrollView) {
56
- _.assign(this.animationDriver, driver);
70
+ const { onAnimationDriverChange } = this.props;
57
71
  const { driverProvider } = this.context;
72
+
73
+ _.assign(this.animationDriver, driver);
74
+ if (onAnimationDriverChange) {
75
+ onAnimationDriverChange(driver);
76
+ }
77
+
58
78
  if (driverProvider) {
59
79
  driverProvider.setAnimationDriver(driver, primaryScrollView);
60
80
  }