@shoutem/ui 4.6.3 → 4.6.6-rc.1

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.
@@ -13,26 +13,42 @@ import { View } from './View';
13
13
 
14
14
  const isIos = Platform.OS === 'ios';
15
15
 
16
+ export const DATEPICKER_MODES = {
17
+ DATE: 'date',
18
+ DATETIME: 'datetime',
19
+ TIME: 'time',
20
+ };
21
+
22
+ const DISPLAY_MODES = {
23
+ [DATEPICKER_MODES.DATE]: 'inline',
24
+ [DATEPICKER_MODES.DATETIME]: 'inline',
25
+ [DATEPICKER_MODES.TIME]: 'spinner',
26
+ };
27
+
28
+ function getDisplayMode(mode) {
29
+ if (!isIos || !Object.keys(DISPLAY_MODES).includes(mode)) {
30
+ return 'default';
31
+ }
32
+
33
+ return DISPLAY_MODES[mode];
34
+ }
35
+
16
36
  class DateTimePicker extends PureComponent {
17
37
  constructor(props) {
18
38
  super(props);
19
39
 
20
40
  autoBindReact(this);
21
41
 
42
+ const { mode, value } = props;
43
+
22
44
  this.state = {
45
+ display: getDisplayMode(mode),
23
46
  showPicker: false,
24
- value: props.value,
47
+ showTimePicker: false,
48
+ value,
25
49
  };
26
50
  }
27
51
 
28
- componentDidUpdate() {
29
- if (!isIos) {
30
- const { value } = this.props;
31
-
32
- this.setState({ value });
33
- }
34
- }
35
-
36
52
  handleValueChanged(event, value) {
37
53
  if (isIos) {
38
54
  return this.setState({ value });
@@ -42,10 +58,33 @@ class DateTimePicker extends PureComponent {
42
58
  return this.handleHidePicker();
43
59
  }
44
60
 
61
+ const { mode, onValueChanged } = this.props;
62
+
63
+ const showTimePicker = mode === DATEPICKER_MODES.DATETIME;
64
+
65
+ this.setState({ value, showPicker: false, showTimePicker });
66
+ return !showTimePicker && onValueChanged(value);
67
+ }
68
+
69
+ handleTimeValueChanged(event, selectedValue) {
70
+ if (event.type === 'dismissed') {
71
+ return this.handleHidePicker();
72
+ }
73
+
45
74
  const { onValueChanged } = this.props;
75
+ const { value } = this.state;
46
76
 
47
- this.setState({ showPicker: false });
48
- return onValueChanged(value);
77
+ // Time picker value will override preselected date
78
+ // Use current date from state and only set hours & minutes
79
+ const currentDate = new Date(value);
80
+ const selectedDate = new Date(selectedValue);
81
+ const hour = selectedDate.getHours();
82
+ const minutes = selectedDate.getMinutes();
83
+
84
+ currentDate.setHours(hour, minutes, 0);
85
+
86
+ this.setState({ value: currentDate, showTimePicker: false });
87
+ return onValueChanged(currentDate);
49
88
  }
50
89
 
51
90
  handleShowPicker() {
@@ -66,6 +105,7 @@ class DateTimePicker extends PureComponent {
66
105
 
67
106
  render() {
68
107
  const {
108
+ cancelButtonText,
69
109
  confirmButtonText,
70
110
  is24Hour,
71
111
  mode,
@@ -73,7 +113,7 @@ class DateTimePicker extends PureComponent {
73
113
  style,
74
114
  ...otherProps
75
115
  } = this.props;
76
- const { showPicker, value } = this.state;
116
+ const { display, showPicker, showTimePicker, value } = this.state;
77
117
 
78
118
  return (
79
119
  <View styleName="horizontal">
@@ -82,7 +122,7 @@ class DateTimePicker extends PureComponent {
82
122
  style={style.textContainer}
83
123
  onPress={this.handleShowPicker}
84
124
  >
85
- <Text> {textValue}</Text>
125
+ <Text>{textValue}</Text>
86
126
  </TouchableOpacity>
87
127
  <TouchableOpacity
88
128
  onPress={this.handleShowPicker}
@@ -91,7 +131,7 @@ class DateTimePicker extends PureComponent {
91
131
  >
92
132
  <Icon name="drop-down" style={style.icon} />
93
133
  </TouchableOpacity>
94
- {isIos && (
134
+ {isIos && showPicker && (
95
135
  <Modal
96
136
  backdropOpacity={0.5}
97
137
  isVisible={showPicker}
@@ -103,7 +143,7 @@ class DateTimePicker extends PureComponent {
103
143
  >
104
144
  <View styleName="md-gutter" style={style.modalContainer}>
105
145
  <RNCDateTimePicker
106
- display="spinner"
146
+ display={display}
107
147
  is24Hour={is24Hour}
108
148
  mode={mode}
109
149
  onChange={this.handleValueChanged}
@@ -114,8 +154,14 @@ class DateTimePicker extends PureComponent {
114
154
  />
115
155
  <View
116
156
  style={style.modalButtonContainer}
117
- styleName="md-gutter-top"
157
+ styleName="horizontal md-gutter-top"
118
158
  >
159
+ <Button
160
+ style={style.modalButton}
161
+ onPress={this.handleHidePicker}
162
+ >
163
+ <Text>{cancelButtonText}</Text>
164
+ </Button>
119
165
  <Button
120
166
  style={style.modalButton}
121
167
  onPress={this.handleConfirmPress}
@@ -128,7 +174,7 @@ class DateTimePicker extends PureComponent {
128
174
  )}
129
175
  {!isIos && showPicker && (
130
176
  <RNCDateTimePicker
131
- display="default"
177
+ display={display}
132
178
  is24Hour={is24Hour}
133
179
  mode={mode}
134
180
  onChange={this.handleValueChanged}
@@ -136,21 +182,33 @@ class DateTimePicker extends PureComponent {
136
182
  {...otherProps}
137
183
  />
138
184
  )}
185
+ {!isIos && !showPicker && showTimePicker && (
186
+ <RNCDateTimePicker
187
+ display={display}
188
+ is24Hour={is24Hour}
189
+ mode="time"
190
+ onChange={this.handleTimeValueChanged}
191
+ value={value}
192
+ {...otherProps}
193
+ />
194
+ )}
139
195
  </View>
140
196
  );
141
197
  }
142
198
  }
143
199
 
144
200
  DateTimePicker.propTypes = {
201
+ cancelButtonText: PropTypes.string,
145
202
  confirmButtonText: PropTypes.string,
146
203
  is24Hour: PropTypes.bool,
147
- mode: PropTypes.string,
204
+ mode: PropTypes.oneOf(Object.values(DATEPICKER_MODES)),
148
205
  onValueChanged: PropTypes.func,
149
206
  textValue: PropTypes.string,
150
207
  value: PropTypes.oneOfType([PropTypes.string, PropTypes.instanceOf(Date)]),
151
208
  };
152
209
 
153
210
  DateTimePicker.defaultProps = {
211
+ cancelButtonText: 'Cancel',
154
212
  confirmButtonText: 'Confirm',
155
213
  is24Hour: false,
156
214
  mode: 'datetime',
@@ -197,9 +197,9 @@ class ListView extends PureComponent {
197
197
  // reference
198
198
  mappedProps.ref = this.handleListViewRef;
199
199
 
200
- mappedProps.onMomentumScrollBegin = this.setIsScrolling(true);
201
-
202
- mappedProps.onMomentumScrollEnd = this.setIsScrolling(false);
200
+ mappedProps.onMomentumScrollBegin = this.setStartedScrolling;
201
+
202
+ mappedProps.onMomentumScrollEnd = this.setEndedScrolling;
203
203
 
204
204
  return mappedProps;
205
205
  }
@@ -221,8 +221,12 @@ class ListView extends PureComponent {
221
221
  }
222
222
  }
223
223
 
224
- setIsScrolling(isScrolling) {
225
- this.setState({ isScrolling });
224
+ setStartedScrolling() {
225
+ this.setState({ isScrolling: true });
226
+ }
227
+
228
+ setEndedScrolling() {
229
+ this.setState({ isScrolling: true });
226
230
  }
227
231
 
228
232
  autoHideHeader({
@@ -25,6 +25,34 @@ import getEmptyObjectKeys from '../services/getEmptyObjectKeys';
25
25
  import isValidVideoFormat from '../services/isValidVideoFormat';
26
26
  import Image from './Image';
27
27
 
28
+ function resolveMaxWidth(style) {
29
+ // parentContainerPadding - padding between screen & SimpleHtml. Parent container
30
+ // can have it's own padding. If it does, we have to include it in calculation,
31
+ // otherwise maxWidth will be more than max & images will go over the edge
32
+ const parentContainerPadding = style.outerPadding || 0;
33
+ const paddingValue =
34
+ style.container.paddingLeft ||
35
+ 0 + style.container.paddingRight ||
36
+ 0 + parentContainerPadding;
37
+
38
+ return Dimensions.get('window').width - paddingValue;
39
+ }
40
+
41
+ function resolveDimensions(objectToResize, style) {
42
+ const { width, height } = objectToResize;
43
+
44
+ if (!width || !height) {
45
+ return { width, height };
46
+ }
47
+
48
+ const maxWidth = resolveMaxWidth(style);
49
+ const objectToResizeRatio = height / width;
50
+ const resolvedWidth = width > maxWidth ? maxWidth : width;
51
+ const resolvedHeight = Math.round(resolvedWidth * objectToResizeRatio);
52
+
53
+ return { width: resolvedWidth, height: resolvedHeight };
54
+ }
55
+
28
56
  class SimpleHtml extends PureComponent {
29
57
  static propTypes = {
30
58
  body: PropTypes.string,
@@ -94,23 +122,15 @@ class SimpleHtml extends PureComponent {
94
122
  }
95
123
  }
96
124
 
97
- const nodeWidth = _.get(node, 'attribs.width', false);
125
+ const nodeWidth = node.attribs?.width;
98
126
 
99
127
  if (!styleAttrib && !nodeWidth) {
100
128
  return false;
101
129
  }
102
130
 
103
- // parentContainerPadding - padding between screen & SimpleHtml. Parent container
104
- // can have it's own padding. If it does, we have to include it in calculation,
105
- // otherwise maxWidth will be more than max & images will go over the edge
106
- const parentContainerPadding = style.outerPadding || 0;
107
- const paddingValue =
108
- _.get(style, 'container.paddingLeft') * 2 + parentContainerPadding;
109
- const maxWidth = Dimensions.get('window').width - paddingValue;
110
- const nodeHeight = _.get(node, 'attribus.height');
111
- const nodeRatio = nodeWidth / nodeHeight;
112
- const resolvedWidth = nodeWidth > maxWidth ? maxWidth : nodeWidth;
113
- const resolvedHeight = Math.round(resolvedWidth * nodeRatio);
131
+ const nodeHeight = node.attribus?.height;
132
+ const nodeDimensions = { width: nodeWidth, height: nodeHeight };
133
+ const { width, height } = resolveDimensions(nodeDimensions, style);
114
134
 
115
135
  const nodeStyle = cssStringToObject(styleAttrib);
116
136
  const invalidKeys = getEmptyObjectKeys(nodeStyle);
@@ -118,8 +138,8 @@ class SimpleHtml extends PureComponent {
118
138
  if (invalidKeys.length || nodeWidth) {
119
139
  const styleFiltered = _.omit(style, invalidKeys);
120
140
  node.attribs.style = cssObjectToString(styleFiltered);
121
- node.attribs.width = resolvedWidth;
122
- node.attribs.height = resolvedHeight;
141
+ node.attribs.width = width;
142
+ node.attribs.height = height;
123
143
 
124
144
  return node;
125
145
  }
@@ -175,7 +195,7 @@ class SimpleHtml extends PureComponent {
175
195
  * Currently only supports rendering image attachments.
176
196
  */
177
197
  renderAttachments({ id, type }) {
178
- const { attachments } = this.props;
198
+ const { attachments, style } = this.props;
179
199
 
180
200
  if (!attachments) {
181
201
  return null;
@@ -186,9 +206,11 @@ class SimpleHtml extends PureComponent {
186
206
 
187
207
  if (image && image.src) {
188
208
  const source = { uri: image.src };
189
- const style = { height: image.height, alignSelf: 'center' };
209
+ const imageSize = { width: image.width, height: image.height };
210
+ const { height, width } = resolveDimensions(imageSize, style);
211
+ const resolvedStyle = { alignSelf: 'center', height, width };
190
212
 
191
- return <Image source={source} key={id} style={style} />;
213
+ return <Image source={source} key={id} style={resolvedStyle} />;
192
214
  }
193
215
  }
194
216
 
@@ -238,13 +260,7 @@ class SimpleHtml extends PureComponent {
238
260
  render() {
239
261
  const { style, body, customTagStyles, ...otherProps } = this.props;
240
262
 
241
- // parentContainerPadding - padding between screen & SimpleHtml. Parent container
242
- // can have it's own padding. If it does, we have to include it in calculation,
243
- // otherwise maxWidth will be more than max & images will go over the edge
244
- const parentContainerPadding = style.outerPadding || 0;
245
- const paddingValue =
246
- _.get(style, 'container.paddingLeft') * 2 + parentContainerPadding;
247
- const maxWidth = Dimensions.get('window').width - paddingValue;
263
+ const maxWidth = resolveMaxWidth(style);
248
264
 
249
265
  const tagStyles = {
250
266
  ...style.tags,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shoutem/ui",
3
- "version": "4.6.3",
3
+ "version": "4.6.6-rc.1",
4
4
  "description": "Styleable set of components for React Native applications",
5
5
  "scripts": {
6
6
  "lint": "eslint .",
package/theme.js CHANGED
@@ -900,6 +900,8 @@ export default (variables = defaultThemeVariables) => ({
900
900
  },
901
901
 
902
902
  'shoutem.ui.Screen': {
903
+ [INCLUDE]: ['commonVariants', 'guttersPadding'],
904
+
903
905
  '.full-screen': {
904
906
  marginTop: -(NAVIGATION_BAR_HEIGHT + StyleSheet.hairlineWidth),
905
907
  },