@shoutem/ui 9.0.0-rc.3 → 9.0.0-rc.5
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.
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import React, { useEffect, useRef, useState } from 'react';
|
|
2
|
-
import { Animated } from 'react-native';
|
|
2
|
+
import { Animated, ScrollView } from 'react-native';
|
|
3
3
|
import PropTypes from 'prop-types';
|
|
4
4
|
import { connectStyle } from '@shoutem/theme';
|
|
5
|
-
import { ScrollView } from './ScrollView';
|
|
6
5
|
import { Text } from './Text';
|
|
7
6
|
|
|
8
7
|
const DEFAULT_CONFIG = {
|
|
@@ -10,7 +9,7 @@ const DEFAULT_CONFIG = {
|
|
|
10
9
|
waitDuration: 2000,
|
|
11
10
|
};
|
|
12
11
|
|
|
13
|
-
const AnimatedScrollingText = ({ text, config, style }) => {
|
|
12
|
+
const AnimatedScrollingText = ({ text, config = DEFAULT_CONFIG, style }) => {
|
|
14
13
|
const translateX = useRef(new Animated.Value(0)).current;
|
|
15
14
|
|
|
16
15
|
const [containerWidth, setContainerWidth] = useState();
|
|
@@ -84,12 +83,12 @@ const AnimatedScrollingText = ({ text, config, style }) => {
|
|
|
84
83
|
|
|
85
84
|
AnimatedScrollingText.propTypes = {
|
|
86
85
|
text: PropTypes.string.isRequired,
|
|
86
|
+
// eslint-disable-next-line react/require-default-props
|
|
87
87
|
config: PropTypes.object,
|
|
88
88
|
style: PropTypes.object,
|
|
89
89
|
};
|
|
90
90
|
|
|
91
91
|
AnimatedScrollingText.defaultProps = {
|
|
92
|
-
config: DEFAULT_CONFIG,
|
|
93
92
|
style: {},
|
|
94
93
|
};
|
|
95
94
|
|
|
@@ -6,6 +6,11 @@ import PropTypes from 'prop-types';
|
|
|
6
6
|
import { AnimationDriverContext, ScrollDriver } from '@shoutem/animation';
|
|
7
7
|
import { connectStyle } from '@shoutem/theme';
|
|
8
8
|
|
|
9
|
+
// ScrollView component envisioned to be used as a container component inside
|
|
10
|
+
// the Shoutem screens. It will correctly set the current animation driver
|
|
11
|
+
// when it is mounted inside the parent screen. In case you don't want the scroll
|
|
12
|
+
// that is aware of the animation driver context, but want the shoutem themed styling,
|
|
13
|
+
// you should use the plain RN ScrollView and connect it to the 'shoutem.ui.ScrollView' stylename
|
|
9
14
|
const ScrollView = ({ driver, onScroll, primary, style, ...otherProps }) => {
|
|
10
15
|
const animationDriver = useRef(
|
|
11
16
|
driver ||
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, {
|
|
1
|
+
import React, { useCallback, useMemo } from 'react';
|
|
2
2
|
import { Linking } from 'react-native';
|
|
3
3
|
import Html, { defaultSystemFonts } from 'react-native-render-html';
|
|
4
4
|
import WebView from 'react-native-webview';
|
|
@@ -8,9 +8,7 @@ import table, {
|
|
|
8
8
|
defaultTableStylesSpecs,
|
|
9
9
|
tableModel,
|
|
10
10
|
} from '@native-html/table-plugin';
|
|
11
|
-
import autoBindReact from 'auto-bind/react';
|
|
12
11
|
import _ from 'lodash';
|
|
13
|
-
import PropTypes from 'prop-types';
|
|
14
12
|
import { connectStyle } from '@shoutem/theme';
|
|
15
13
|
import VideoRenderer from '@shoutem/ui/html/components/VideoRenderer';
|
|
16
14
|
import { videoModel } from '@shoutem/ui/html/services/HTMLElementModels';
|
|
@@ -20,52 +18,53 @@ import { onElement } from '../services/DomVisitors';
|
|
|
20
18
|
import AttachmentRenderer from './AttachmentRenderer';
|
|
21
19
|
import IframeRenderer from './IframeRenderer';
|
|
22
20
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
21
|
+
const SimpleHtml = ({
|
|
22
|
+
style,
|
|
23
|
+
body,
|
|
24
|
+
unsupportedVideoFormatMessage,
|
|
25
|
+
attachments,
|
|
26
|
+
customDomVisitors = {},
|
|
27
|
+
customCustomRenderers = {},
|
|
28
|
+
customTagStyles = {},
|
|
29
|
+
customHtmlElementModels = {},
|
|
30
|
+
customIgnoredStyles = [],
|
|
31
|
+
customRendererProps = {},
|
|
32
|
+
customHandleLinkPress,
|
|
33
|
+
...otherProps
|
|
34
|
+
}) => {
|
|
35
|
+
const onLinkPress = useCallback(
|
|
36
|
+
(_evt, href) => {
|
|
37
|
+
return customHandleLinkPress
|
|
38
|
+
? customHandleLinkPress(href)
|
|
39
|
+
: Linking.openURL(href);
|
|
40
|
+
},
|
|
41
|
+
[customHandleLinkPress],
|
|
42
|
+
);
|
|
26
43
|
|
|
27
|
-
|
|
28
|
-
|
|
44
|
+
const maxWidth = useMemo(() => {
|
|
45
|
+
return resolveMaxWidth(style);
|
|
46
|
+
}, [style]);
|
|
29
47
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
return customHandleLinkPress
|
|
34
|
-
? customHandleLinkPress(href)
|
|
35
|
-
: Linking.openURL(href);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
render() {
|
|
39
|
-
const {
|
|
40
|
-
style,
|
|
41
|
-
body,
|
|
42
|
-
unsupportedVideoFormatMessage,
|
|
43
|
-
attachments,
|
|
44
|
-
customDomVisitors,
|
|
45
|
-
customCustomRenderers,
|
|
46
|
-
customTagStyles,
|
|
47
|
-
customHtmlElementModels,
|
|
48
|
-
customIgnoredStyles,
|
|
49
|
-
customRendererProps,
|
|
50
|
-
...otherProps
|
|
51
|
-
} = this.props;
|
|
52
|
-
|
|
53
|
-
const maxWidth = resolveMaxWidth(style);
|
|
54
|
-
|
|
55
|
-
const tagStyles = {
|
|
48
|
+
const tagStyles = useMemo(
|
|
49
|
+
() => ({
|
|
56
50
|
...style.tags,
|
|
57
51
|
...customTagStyles,
|
|
58
|
-
}
|
|
52
|
+
}),
|
|
53
|
+
[style.tags, customTagStyles],
|
|
54
|
+
);
|
|
59
55
|
|
|
56
|
+
const cssRules = useMemo(() => {
|
|
60
57
|
const tableStyle = _.get(style, 'table', {});
|
|
61
58
|
const tableCssStyle = _.get(style, 'tableCss', '');
|
|
62
59
|
const cssStyle = cssRulesFromSpecs({
|
|
63
60
|
...defaultTableStylesSpecs,
|
|
64
61
|
...tableStyle,
|
|
65
62
|
});
|
|
66
|
-
|
|
63
|
+
return `${cssStyle}${tableCssStyle}`;
|
|
64
|
+
}, [style]);
|
|
67
65
|
|
|
68
|
-
|
|
66
|
+
const customRenderers = useMemo(
|
|
67
|
+
() => ({
|
|
69
68
|
iframe: props => (
|
|
70
69
|
<IframeRenderer
|
|
71
70
|
{...props}
|
|
@@ -83,79 +82,87 @@ class SimpleHtml extends PureComponent {
|
|
|
83
82
|
),
|
|
84
83
|
video: VideoRenderer,
|
|
85
84
|
...customCustomRenderers,
|
|
86
|
-
}
|
|
85
|
+
}),
|
|
86
|
+
[style, unsupportedVideoFormatMessage, attachments, customCustomRenderers],
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
const systemFonts = useMemo(
|
|
90
|
+
() => [...defaultSystemFonts, style.baseFont.fontFamily],
|
|
91
|
+
[style.baseFont.fontFamily],
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
const ignoredStyles = useMemo(
|
|
95
|
+
() => ['fontFamily', 'letterSpacing', 'transform', ...customIgnoredStyles],
|
|
96
|
+
[customIgnoredStyles],
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
const renderersProps = useMemo(
|
|
100
|
+
() => ({
|
|
101
|
+
table: {
|
|
102
|
+
cssRules,
|
|
103
|
+
},
|
|
104
|
+
a: { onPress: onLinkPress },
|
|
105
|
+
iframe: {
|
|
106
|
+
webViewProps: {
|
|
107
|
+
renderToHardwareTextureAndroid: true,
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
...customRendererProps,
|
|
111
|
+
}),
|
|
112
|
+
[cssRules, onLinkPress, customRendererProps],
|
|
113
|
+
);
|
|
87
114
|
|
|
88
|
-
|
|
115
|
+
const customHTMLElementModels = useMemo(
|
|
116
|
+
() => ({
|
|
117
|
+
table: tableModel,
|
|
118
|
+
iframe: iframeModel,
|
|
119
|
+
video: videoModel,
|
|
120
|
+
...customHtmlElementModels,
|
|
121
|
+
}),
|
|
122
|
+
[customHtmlElementModels],
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
const domVisitors = useMemo(
|
|
126
|
+
() => ({
|
|
127
|
+
onElement,
|
|
128
|
+
...customDomVisitors,
|
|
129
|
+
}),
|
|
130
|
+
[customDomVisitors],
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
const filteredTagStyles = useMemo(
|
|
134
|
+
() => _.omitBy(tagStyles, tagStyle => !tagStyle),
|
|
135
|
+
[tagStyles],
|
|
136
|
+
);
|
|
137
|
+
|
|
138
|
+
// We have to be really careful with props passed to SimpleHtml, as they'll cause unnecessary re-renders.
|
|
139
|
+
// Component is meant to be static (in almost all scenarios) - it should only render with initially given props.
|
|
140
|
+
// Notice that props below are memoized to only be calculated on mount, because lots of these props non-primitive
|
|
141
|
+
// (reference types), and they'll cause re-renders.
|
|
142
|
+
const htmlProps = useMemo(
|
|
143
|
+
() => ({
|
|
89
144
|
source: { html: body },
|
|
90
145
|
computeEmbeddedMaxWidth: () => maxWidth,
|
|
91
146
|
contentWidth: maxWidth,
|
|
92
|
-
tagsStyles:
|
|
93
|
-
systemFonts
|
|
147
|
+
tagsStyles: filteredTagStyles,
|
|
148
|
+
systemFonts,
|
|
94
149
|
baseStyle: style.baseFont,
|
|
95
|
-
ignoredStyles
|
|
96
|
-
'fontFamily',
|
|
97
|
-
'letterSpacing',
|
|
98
|
-
'transform',
|
|
99
|
-
...customIgnoredStyles,
|
|
100
|
-
],
|
|
150
|
+
ignoredStyles,
|
|
101
151
|
renderers: customRenderers,
|
|
102
|
-
renderersProps
|
|
103
|
-
|
|
104
|
-
cssRules,
|
|
105
|
-
},
|
|
106
|
-
a: { onPress: this.onLinkPress },
|
|
107
|
-
iframe: {
|
|
108
|
-
webViewProps: {
|
|
109
|
-
renderToHardwareTextureAndroid: true,
|
|
110
|
-
},
|
|
111
|
-
},
|
|
112
|
-
...customRendererProps,
|
|
113
|
-
},
|
|
114
|
-
customHTMLElementModels: {
|
|
115
|
-
table: tableModel,
|
|
116
|
-
iframe: iframeModel,
|
|
117
|
-
video: videoModel,
|
|
118
|
-
...customHtmlElementModels,
|
|
119
|
-
},
|
|
152
|
+
renderersProps,
|
|
153
|
+
customHTMLElementModels,
|
|
120
154
|
WebView,
|
|
121
|
-
domVisitors
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
<Html {...htmlProps} {...otherProps} />
|
|
127
|
-
</View>
|
|
128
|
-
);
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
SimpleHtml.propTypes = {
|
|
133
|
-
style: PropTypes.object.isRequired,
|
|
134
|
-
attachments: PropTypes.array,
|
|
135
|
-
body: PropTypes.string,
|
|
136
|
-
customCustomRenderers: PropTypes.object,
|
|
137
|
-
customDomVisitors: PropTypes.object,
|
|
138
|
-
customHandleLinkPress: PropTypes.func,
|
|
139
|
-
customHtmlElementModels: PropTypes.object,
|
|
140
|
-
customIgnoredStyles: PropTypes.arrayOf(PropTypes.string),
|
|
141
|
-
customRendererProps: PropTypes.object,
|
|
142
|
-
customTagStyles: PropTypes.object,
|
|
143
|
-
domVisitors: PropTypes.object,
|
|
144
|
-
unsupportedVideoFormatMessage: PropTypes.string,
|
|
145
|
-
};
|
|
155
|
+
domVisitors,
|
|
156
|
+
}),
|
|
157
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
158
|
+
[],
|
|
159
|
+
);
|
|
146
160
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
unsupportedVideoFormatMessage: undefined,
|
|
153
|
-
domVisitors: { onElement },
|
|
154
|
-
customDomVisitors: {},
|
|
155
|
-
customCustomRenderers: {},
|
|
156
|
-
customHtmlElementModels: {},
|
|
157
|
-
customIgnoredStyles: [],
|
|
158
|
-
customRendererProps: {},
|
|
161
|
+
return (
|
|
162
|
+
<View style={style.container}>
|
|
163
|
+
<Html {...htmlProps} {...otherProps} />
|
|
164
|
+
</View>
|
|
165
|
+
);
|
|
159
166
|
};
|
|
160
167
|
|
|
161
|
-
export default connectStyle('shoutem.ui.SimpleHtml')(SimpleHtml);
|
|
168
|
+
export default React.memo(connectStyle('shoutem.ui.SimpleHtml')(SimpleHtml));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shoutem/ui",
|
|
3
|
-
"version": "9.0.0-rc.
|
|
3
|
+
"version": "9.0.0-rc.5",
|
|
4
4
|
"description": "Styleable set of components for React Native applications",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"lint": "eslint .",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"@react-native-community/datetimepicker": "6.2.0",
|
|
18
18
|
"@shoutem/animation": "1.0.0-rc.1",
|
|
19
19
|
"@shoutem/eslint-config-react": "~1.0.6",
|
|
20
|
-
"@shoutem/theme": "1.0.0-rc.
|
|
20
|
+
"@shoutem/theme": "1.0.0-rc.4",
|
|
21
21
|
"auto-bind": "4.0.0",
|
|
22
22
|
"babel-plugin-transform-decorators-legacy": "1.3.5",
|
|
23
23
|
"buffer": "5.6.0",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"react-native-toast-message": "2.1.5",
|
|
42
42
|
"react-native-vimeo-iframe": "^1.2.1",
|
|
43
43
|
"react-native-web-refresh-control": "1.1.2",
|
|
44
|
-
"react-native-webview": "
|
|
44
|
+
"react-native-webview": "13.16.0",
|
|
45
45
|
"react-native-youtube-iframe": "2.2.2",
|
|
46
46
|
"react-native-actions-sheet": "0.9.3",
|
|
47
47
|
"stream": "0.0.2",
|