@shoutem/ui 6.1.2 → 6.3.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.
package/README.md
CHANGED
|
@@ -12,6 +12,14 @@ $ npm install --save @shoutem/ui
|
|
|
12
12
|
|
|
13
13
|
We have a `postinstall` script which will add `@shoutem/ui`'s native dependencies to your root `package.json` in order to support autolinking and pod installation.
|
|
14
14
|
|
|
15
|
+
Optional: Link the font files to your iOS and Android projects using `react-native-asset`:
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
$ npx react-native-asset node_modules/@shoutem/ui/fonts
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Not doing this will result in dismissable red screen errors about unknown font names, as well as the default system fonts being used on iOS and Android when a Shoutem UI font is meant to be used, so we suggest running this step.
|
|
22
|
+
|
|
15
23
|
## Docs
|
|
16
24
|
|
|
17
25
|
All the documentation is available on the [Developer portal](http://shoutem.github.io/docs/ui-toolkit/introduction).
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import _ from 'lodash';
|
|
3
|
+
import PropTypes from 'prop-types';
|
|
4
|
+
import { resolveDimensions } from '../services/Dimensions';
|
|
5
|
+
import Image from './Image';
|
|
6
|
+
|
|
7
|
+
const AttachmentRenderer = ({ id, type, style, attachments }) => {
|
|
8
|
+
if (!attachments) {
|
|
9
|
+
return null;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
if (type === 'image') {
|
|
13
|
+
const image = _.find(attachments, { id });
|
|
14
|
+
|
|
15
|
+
if (image && image.src) {
|
|
16
|
+
const source = { uri: image.src };
|
|
17
|
+
const imageSize = { width: image.width, height: image.height };
|
|
18
|
+
const { height, width } = resolveDimensions(imageSize, style);
|
|
19
|
+
const resolvedStyle = { alignSelf: 'center', height, width };
|
|
20
|
+
|
|
21
|
+
return <Image source={source} key={id} style={resolvedStyle} />;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return null;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
AttachmentRenderer.propTypes = {
|
|
29
|
+
attachments: PropTypes.oneOf([PropTypes.array, PropTypes.object]),
|
|
30
|
+
id: PropTypes.any,
|
|
31
|
+
style: PropTypes.any,
|
|
32
|
+
type: PropTypes.any,
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
AttachmentRenderer.defaultProps = {
|
|
36
|
+
id: undefined,
|
|
37
|
+
type: undefined,
|
|
38
|
+
attachments: undefined,
|
|
39
|
+
style: undefined,
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export default AttachmentRenderer;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import YoutubePlayer from 'react-native-youtube-iframe';
|
|
3
|
+
import iframe from '@native-html/iframe-plugin';
|
|
4
|
+
import PropTypes from 'prop-types';
|
|
5
|
+
import { Text } from '../../components/Text';
|
|
6
|
+
import { View } from '../../components/View';
|
|
7
|
+
import isValidVideoFormat from '../services/isValidVideoFormat';
|
|
8
|
+
|
|
9
|
+
const IframeRenderer = props => {
|
|
10
|
+
const { tnode, shoutemStyle, unsupportedVideoFormatMessage } = props;
|
|
11
|
+
const url = tnode?.domNode?.attribs?.src;
|
|
12
|
+
|
|
13
|
+
if (url && !isValidVideoFormat(url)) {
|
|
14
|
+
const message =
|
|
15
|
+
unsupportedVideoFormatMessage || 'Unsupported video format.';
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
<View
|
|
19
|
+
style={shoutemStyle.fallback}
|
|
20
|
+
styleName="vertical h-center v-center"
|
|
21
|
+
>
|
|
22
|
+
<Text>{message}</Text>
|
|
23
|
+
</View>
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (url && (url.includes('youtube') || url.includes('youtu.be'))) {
|
|
28
|
+
const youtubeIdRegEx = /^.*((youtu.be\/)|(v\/)|(\/u\/\w\/)|(embed\/)|(watch\?))\??v?=?([^#&?]*).*/;
|
|
29
|
+
const regExMatch = url.match(youtubeIdRegEx);
|
|
30
|
+
const youtubeId =
|
|
31
|
+
regExMatch && regExMatch[7].length === 11 ? regExMatch[7] : false;
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
<YoutubePlayer
|
|
35
|
+
webViewProps={{
|
|
36
|
+
renderToHardwareTextureAndroid: true,
|
|
37
|
+
}}
|
|
38
|
+
height={shoutemStyle.video.height}
|
|
39
|
+
videoId={youtubeId}
|
|
40
|
+
/>
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return iframe(props);
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
IframeRenderer.propTypes = {
|
|
48
|
+
tnode: PropTypes.shape({
|
|
49
|
+
children: PropTypes.any,
|
|
50
|
+
}).isRequired,
|
|
51
|
+
shoutemStyle: PropTypes.any,
|
|
52
|
+
unsupportedVideoFormatMessage: PropTypes.string,
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
IframeRenderer.defaultProps = {
|
|
56
|
+
shoutemStyle: undefined,
|
|
57
|
+
unsupportedVideoFormatMessage: undefined,
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export default IframeRenderer;
|
|
@@ -1,57 +1,22 @@
|
|
|
1
1
|
import React, { PureComponent } from 'react';
|
|
2
|
-
import {
|
|
3
|
-
import Html from 'react-native-render-html';
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
cssStringToObject,
|
|
8
|
-
} from 'react-native-render-html/src/HTMLStyles';
|
|
9
|
-
import {
|
|
10
|
-
alterNode as tableAlterNode,
|
|
2
|
+
import { Linking } from 'react-native';
|
|
3
|
+
import Html, { defaultSystemFonts } from 'react-native-render-html';
|
|
4
|
+
import WebView from 'react-native-webview';
|
|
5
|
+
import { iframeModel } from '@native-html/iframe-plugin';
|
|
6
|
+
import table, {
|
|
11
7
|
cssRulesFromSpecs,
|
|
12
8
|
defaultTableStylesSpecs,
|
|
13
9
|
IGNORED_TAGS,
|
|
14
|
-
|
|
15
|
-
} from '
|
|
16
|
-
import WebView from 'react-native-webview';
|
|
17
|
-
import YoutubePlayer from 'react-native-youtube-iframe';
|
|
10
|
+
tableModel,
|
|
11
|
+
} from '@native-html/table-plugin';
|
|
18
12
|
import autoBindReact from 'auto-bind/react';
|
|
19
13
|
import _ from 'lodash';
|
|
20
14
|
import PropTypes from 'prop-types';
|
|
21
15
|
import { connectStyle } from '@shoutem/theme';
|
|
22
|
-
import { Text } from '../../components/Text';
|
|
23
16
|
import { View } from '../../components/View';
|
|
24
|
-
import
|
|
25
|
-
import
|
|
26
|
-
import
|
|
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
|
-
}
|
|
17
|
+
import { resolveMaxWidth } from '../services/Dimensions';
|
|
18
|
+
import AttachmentRenderer from './AttachmentRenderer';
|
|
19
|
+
import IframeRenderer from './IframeRenderer';
|
|
55
20
|
|
|
56
21
|
class SimpleHtml extends PureComponent {
|
|
57
22
|
constructor(props) {
|
|
@@ -60,7 +25,7 @@ class SimpleHtml extends PureComponent {
|
|
|
60
25
|
autoBindReact(this);
|
|
61
26
|
}
|
|
62
27
|
|
|
63
|
-
onLinkPress(
|
|
28
|
+
onLinkPress(_evt, href) {
|
|
64
29
|
const { customHandleLinkPress } = this.props;
|
|
65
30
|
|
|
66
31
|
return customHandleLinkPress
|
|
@@ -68,187 +33,15 @@ class SimpleHtml extends PureComponent {
|
|
|
68
33
|
: Linking.openURL(href);
|
|
69
34
|
}
|
|
70
35
|
|
|
71
|
-
/**
|
|
72
|
-
* Removes empty (therefore invalid) style attribute properties
|
|
73
|
-
* Scales down objects with specified width and height if too large
|
|
74
|
-
* Removes padding and height from suneditor for 'figure' tag that it nests
|
|
75
|
-
* video iframe tags in when video format is unsupported
|
|
76
|
-
*/
|
|
77
|
-
alterNode(node) {
|
|
78
|
-
const { customAlterNode, style } = this.props;
|
|
79
|
-
|
|
80
|
-
const styleAttrib = _.get(node, 'attribs.style', '').trim();
|
|
81
|
-
|
|
82
|
-
if (customAlterNode && _.isFunction(customAlterNode)) {
|
|
83
|
-
const resolvedNode = customAlterNode(
|
|
84
|
-
node,
|
|
85
|
-
cssObjectToString,
|
|
86
|
-
cssStringToObject,
|
|
87
|
-
);
|
|
88
|
-
|
|
89
|
-
if (resolvedNode) {
|
|
90
|
-
return resolvedNode;
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
if (node.name === 'table') {
|
|
95
|
-
return tableAlterNode(node);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
if (node.name === 'figure') {
|
|
99
|
-
const firstChild = _.head(node.children);
|
|
100
|
-
|
|
101
|
-
if (firstChild.name === 'iframe') {
|
|
102
|
-
const nodeStyle = cssStringToObject(styleAttrib);
|
|
103
|
-
const source = _.get(firstChild, 'attribs.src', '');
|
|
104
|
-
|
|
105
|
-
const resolvedNodeStyle = isValidVideoFormat(source)
|
|
106
|
-
? _.omit(nodeStyle, ['height', 'padding-bottom'])
|
|
107
|
-
: nodeStyle;
|
|
108
|
-
|
|
109
|
-
node.attribs.style = cssObjectToString(resolvedNodeStyle);
|
|
110
|
-
|
|
111
|
-
return node;
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
const nodeWidth = node.attribs?.width;
|
|
116
|
-
|
|
117
|
-
if (!styleAttrib && !nodeWidth) {
|
|
118
|
-
return false;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
const nodeHeight = node.attribus?.height;
|
|
122
|
-
const nodeDimensions = { width: nodeWidth, height: nodeHeight };
|
|
123
|
-
const { width, height } = resolveDimensions(nodeDimensions, style);
|
|
124
|
-
|
|
125
|
-
const nodeStyle = cssStringToObject(styleAttrib);
|
|
126
|
-
const invalidKeys = getEmptyObjectKeys(nodeStyle);
|
|
127
|
-
|
|
128
|
-
if (invalidKeys.length || nodeWidth) {
|
|
129
|
-
const styleFiltered = _.omit(style, invalidKeys);
|
|
130
|
-
node.attribs.style = cssObjectToString(styleFiltered);
|
|
131
|
-
node.attribs.width = width;
|
|
132
|
-
node.attribs.height = height;
|
|
133
|
-
|
|
134
|
-
return node;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
return false;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* Removes child break node in case when it's positioned at the end
|
|
142
|
-
* of parent div node and div has content in it.
|
|
143
|
-
* Example:
|
|
144
|
-
* <div>first line<br></div>
|
|
145
|
-
* <div>second line<br></div>
|
|
146
|
-
*
|
|
147
|
-
* If br is left as is, <Html> will show empty line under div, not just
|
|
148
|
-
* break into new line
|
|
149
|
-
*/
|
|
150
|
-
alterChildren(node) {
|
|
151
|
-
const { children, name } = node;
|
|
152
|
-
|
|
153
|
-
if ((name === 'div' || name === 'p') && children && children.length > 1) {
|
|
154
|
-
const brNodes = _.filter(children, { name: 'br' });
|
|
155
|
-
const lastBrNode = _.last(brNodes);
|
|
156
|
-
|
|
157
|
-
if (lastBrNode && lastBrNode.next === null) {
|
|
158
|
-
const lastBrNodeIndex = _.indexOf(children, lastBrNode);
|
|
159
|
-
return children.splice(0, lastBrNodeIndex);
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
return children;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
renderUnorderedListPrefix() {
|
|
167
|
-
const { style } = this.props;
|
|
168
|
-
|
|
169
|
-
return <Text style={style.prefix}>• </Text>;
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
renderOrderedListPrefix(
|
|
173
|
-
htmlAttribs,
|
|
174
|
-
children,
|
|
175
|
-
convertedCSSStyles,
|
|
176
|
-
passProps,
|
|
177
|
-
) {
|
|
178
|
-
const { style } = this.props;
|
|
179
|
-
|
|
180
|
-
return <Text style={style.prefix}>{passProps.index + 1}. </Text>;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
/**
|
|
184
|
-
* Custom rendered method for handling <attachment> tags
|
|
185
|
-
* Currently only supports rendering image attachments.
|
|
186
|
-
*/
|
|
187
|
-
renderAttachments({ id, type }) {
|
|
188
|
-
const { attachments, style } = this.props;
|
|
189
|
-
|
|
190
|
-
if (!attachments) {
|
|
191
|
-
return null;
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
if (type === 'image') {
|
|
195
|
-
const image = _.find(attachments, { id });
|
|
196
|
-
|
|
197
|
-
if (image && image.src) {
|
|
198
|
-
const source = { uri: image.src };
|
|
199
|
-
const imageSize = { width: image.width, height: image.height };
|
|
200
|
-
const { height, width } = resolveDimensions(imageSize, style);
|
|
201
|
-
const resolvedStyle = { alignSelf: 'center', height, width };
|
|
202
|
-
|
|
203
|
-
return <Image source={source} key={id} style={resolvedStyle} />;
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
return null;
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
renderIframe(htmlAttribs, children, convertedCSSStyles, passProps) {
|
|
211
|
-
const { style } = this.props;
|
|
212
|
-
|
|
213
|
-
const url = htmlAttribs?.src;
|
|
214
|
-
|
|
215
|
-
if (url && !isValidVideoFormat(url)) {
|
|
216
|
-
const { unsupportedVideoFormatMessage } = this.props;
|
|
217
|
-
|
|
218
|
-
const message =
|
|
219
|
-
unsupportedVideoFormatMessage || 'Unsupported video format.';
|
|
220
|
-
|
|
221
|
-
return (
|
|
222
|
-
<View
|
|
223
|
-
style={style.fallback}
|
|
224
|
-
styleName="vertical h-center v-center"
|
|
225
|
-
key={passProps.key}
|
|
226
|
-
>
|
|
227
|
-
<Text>{message}</Text>
|
|
228
|
-
</View>
|
|
229
|
-
);
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
if (url && (url.includes('youtube') || url.includes('youtu.be'))) {
|
|
233
|
-
const youtubeIdRegEx = /^.*((youtu.be\/)|(v\/)|(\/u\/\w\/)|(embed\/)|(watch\?))\??v?=?([^#&?]*).*/;
|
|
234
|
-
const regExMatch = url.match(youtubeIdRegEx);
|
|
235
|
-
const youtubeId =
|
|
236
|
-
regExMatch && regExMatch[7].length === 11 ? regExMatch[7] : false;
|
|
237
|
-
|
|
238
|
-
return (
|
|
239
|
-
<YoutubePlayer
|
|
240
|
-
height={style.video.height}
|
|
241
|
-
key={passProps.key}
|
|
242
|
-
videoId={youtubeId}
|
|
243
|
-
/>
|
|
244
|
-
);
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
return iframe(htmlAttribs, children, convertedCSSStyles, passProps);
|
|
248
|
-
}
|
|
249
|
-
|
|
250
36
|
render() {
|
|
251
|
-
const {
|
|
37
|
+
const {
|
|
38
|
+
style,
|
|
39
|
+
body,
|
|
40
|
+
customTagStyles,
|
|
41
|
+
unsupportedVideoFormatMessage,
|
|
42
|
+
attachments,
|
|
43
|
+
...otherProps
|
|
44
|
+
} = this.props;
|
|
252
45
|
|
|
253
46
|
const maxWidth = resolveMaxWidth(style);
|
|
254
47
|
|
|
@@ -257,11 +50,6 @@ class SimpleHtml extends PureComponent {
|
|
|
257
50
|
...customTagStyles,
|
|
258
51
|
};
|
|
259
52
|
|
|
260
|
-
const listPrefixRenderers = {
|
|
261
|
-
ul: this.renderUnorderedListPrefix,
|
|
262
|
-
ol: this.renderOrderedListPrefix,
|
|
263
|
-
};
|
|
264
|
-
|
|
265
53
|
const tableStyle = _.get(style, 'table', {});
|
|
266
54
|
const tableCssStyle = _.get(style, 'tableCss', '');
|
|
267
55
|
const cssStyle = cssRulesFromSpecs({
|
|
@@ -271,23 +59,48 @@ class SimpleHtml extends PureComponent {
|
|
|
271
59
|
const cssRules = `${cssStyle}${tableCssStyle}`;
|
|
272
60
|
|
|
273
61
|
const customRenderers = {
|
|
274
|
-
iframe:
|
|
275
|
-
|
|
276
|
-
|
|
62
|
+
iframe: props => (
|
|
63
|
+
<IframeRenderer
|
|
64
|
+
{...props}
|
|
65
|
+
shoutemStyle={style}
|
|
66
|
+
unsupportedVideoFormatMessage={unsupportedVideoFormatMessage}
|
|
67
|
+
/>
|
|
68
|
+
),
|
|
69
|
+
table,
|
|
70
|
+
attachment: props => (
|
|
71
|
+
<AttachmentRenderer
|
|
72
|
+
{...props}
|
|
73
|
+
attachments={attachments}
|
|
74
|
+
style={style}
|
|
75
|
+
/>
|
|
76
|
+
),
|
|
277
77
|
};
|
|
278
78
|
|
|
279
79
|
const htmlProps = {
|
|
280
|
-
html: body,
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
tagsStyles: tagStyles,
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
alterNode: this.alterNode,
|
|
288
|
-
alterChildren: this.alterChildren,
|
|
289
|
-
listsPrefixesRenderers: listPrefixRenderers,
|
|
80
|
+
source: { html: body },
|
|
81
|
+
computeEmbeddedMaxWidth: () => maxWidth,
|
|
82
|
+
contentWidth: maxWidth,
|
|
83
|
+
tagsStyles: _.omitBy(tagStyles, tagStyle => !tagStyle),
|
|
84
|
+
systemFonts: [...defaultSystemFonts, style.baseFont.fontFamily],
|
|
85
|
+
baseStyle: style.baseFont,
|
|
86
|
+
ignoredStyles: ['fontFamily', 'letterSpacing', 'transform'],
|
|
290
87
|
renderers: customRenderers,
|
|
88
|
+
renderersProps: {
|
|
89
|
+
table: {
|
|
90
|
+
cssRules,
|
|
91
|
+
},
|
|
92
|
+
a: { onPress: this.onLinkPress },
|
|
93
|
+
iframe: {
|
|
94
|
+
webViewProps: {
|
|
95
|
+
renderToHardwareTextureAndroid: true,
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
customHTMLElementModels: {
|
|
100
|
+
table: tableModel,
|
|
101
|
+
iframe: iframeModel,
|
|
102
|
+
},
|
|
103
|
+
WebView,
|
|
291
104
|
ignoredTags: IGNORED_TAGS,
|
|
292
105
|
};
|
|
293
106
|
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Dimensions } from 'react-native';
|
|
2
|
+
|
|
3
|
+
export function resolveMaxWidth(style) {
|
|
4
|
+
// parentContainerPadding - padding between screen & SimpleHtml. Parent container
|
|
5
|
+
// can have it's own padding. If it does, we have to include it in calculation,
|
|
6
|
+
// otherwise maxWidth will be more than max & images will go over the edge
|
|
7
|
+
const parentContainerPadding = style.outerPadding || 0;
|
|
8
|
+
const paddingValue =
|
|
9
|
+
style.container.paddingLeft ||
|
|
10
|
+
0 + style.container.paddingRight ||
|
|
11
|
+
0 + parentContainerPadding;
|
|
12
|
+
|
|
13
|
+
return Dimensions.get('window').width - paddingValue;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function resolveDimensions(objectToResize, style) {
|
|
17
|
+
const { width, height } = objectToResize;
|
|
18
|
+
|
|
19
|
+
if (!width || !height) {
|
|
20
|
+
return { width, height };
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const maxWidth = resolveMaxWidth(style);
|
|
24
|
+
const objectToResizeRatio = height / width;
|
|
25
|
+
const resolvedWidth = width > maxWidth ? maxWidth : width;
|
|
26
|
+
const resolvedHeight = Math.round(resolvedWidth * objectToResizeRatio);
|
|
27
|
+
|
|
28
|
+
return { width: resolvedWidth, height: resolvedHeight };
|
|
29
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shoutem/ui",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.3.0",
|
|
4
4
|
"description": "Styleable set of components for React Native applications",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"lint": "eslint .",
|
|
@@ -16,6 +16,8 @@
|
|
|
16
16
|
"@shoutem/animation": "~0.15.0",
|
|
17
17
|
"@shoutem/eslint-config-react": "~1.0.6",
|
|
18
18
|
"@shoutem/theme": "~0.13.0",
|
|
19
|
+
"@native-html/iframe-plugin": "2.6.1",
|
|
20
|
+
"@native-html/table-plugin": "5.3.1",
|
|
19
21
|
"auto-bind": "4.0.0",
|
|
20
22
|
"babel-plugin-transform-decorators-legacy": "1.3.5",
|
|
21
23
|
"buffer": "5.6.0",
|
|
@@ -25,16 +27,15 @@
|
|
|
25
27
|
"html-entities": "1.3.1",
|
|
26
28
|
"htmlparser2": "3.10.1",
|
|
27
29
|
"lodash": "4.17.21",
|
|
28
|
-
"lottie-ios": "
|
|
29
|
-
"lottie-react-native": "
|
|
30
|
+
"lottie-ios": "4.2.0",
|
|
31
|
+
"lottie-react-native": "6.1.2",
|
|
30
32
|
"prop-types": "15.8.1",
|
|
31
33
|
"qs": "6.9.3",
|
|
32
34
|
"react-native-device-info": "9.0.2",
|
|
33
35
|
"react-native-lightbox-v2": "0.9.0",
|
|
34
36
|
"react-native-linear-gradient": "2.6.2",
|
|
35
|
-
"react-native-modal": "
|
|
36
|
-
"react-native-render-html": "
|
|
37
|
-
"react-native-render-html-table-bridge": "0.6.0",
|
|
37
|
+
"react-native-modal": "13.0.1",
|
|
38
|
+
"react-native-render-html": "6.3.4",
|
|
38
39
|
"react-native-svg": "12.3.0",
|
|
39
40
|
"react-native-svg-transformer": "1.0.0",
|
|
40
41
|
"react-native-toast-message": "2.1.5",
|
|
@@ -63,9 +64,10 @@
|
|
|
63
64
|
"eslint-plugin-simple-import-sort": "7.0.0",
|
|
64
65
|
"jest": "27.5.1",
|
|
65
66
|
"metro-react-native-babel-preset": "0.66.2",
|
|
67
|
+
"path": "0.12.7",
|
|
66
68
|
"prettier": "1.19.1",
|
|
67
69
|
"react": "17.0.2",
|
|
68
|
-
"react-dom": "
|
|
70
|
+
"react-dom": "17.0.2",
|
|
69
71
|
"react-native": "0.68.2",
|
|
70
72
|
"react-test-renderer": "17.0.2"
|
|
71
73
|
},
|
|
@@ -88,7 +90,11 @@
|
|
|
88
90
|
"url": "git+ssh://git@github.com:shoutem/ui.git"
|
|
89
91
|
},
|
|
90
92
|
"license": "BSD-3-Clause",
|
|
91
|
-
"
|
|
93
|
+
"contributors": [
|
|
94
|
+
{
|
|
95
|
+
"email": "majaklajic@gmail.com",
|
|
96
|
+
"name": "majaklajic"
|
|
97
|
+
},
|
|
92
98
|
{
|
|
93
99
|
"email": "lucija.tatarevic@shoutem.com",
|
|
94
100
|
"name": "ltatarev"
|
|
@@ -129,4 +135,4 @@
|
|
|
129
135
|
"!/node_modules/@shoutem"
|
|
130
136
|
]
|
|
131
137
|
}
|
|
132
|
-
}
|
|
138
|
+
}
|