@shoutem/ui 6.3.2 → 6.3.3-rc.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.
@@ -13,6 +13,8 @@ import autoBindReact from 'auto-bind/react';
13
13
  import _ from 'lodash';
14
14
  import PropTypes from 'prop-types';
15
15
  import { connectStyle } from '@shoutem/theme';
16
+ import VideoRenderer from '@shoutem/ui/html/components/VideoRenderer';
17
+ import { videoModel } from '@shoutem/ui/html/services/HTMLElementModels';
16
18
  import { View } from '../../components/View';
17
19
  import { resolveMaxWidth } from '../services/Dimensions';
18
20
  import { onElement } from '../services/DomVisitors';
@@ -76,6 +78,7 @@ class SimpleHtml extends PureComponent {
76
78
  style={style}
77
79
  />
78
80
  ),
81
+ video: VideoRenderer,
79
82
  };
80
83
 
81
84
  const htmlProps = {
@@ -101,10 +104,11 @@ class SimpleHtml extends PureComponent {
101
104
  customHTMLElementModels: {
102
105
  table: tableModel,
103
106
  iframe: iframeModel,
107
+ video: videoModel,
104
108
  },
105
109
  WebView,
106
110
  ignoredTags: IGNORED_TAGS,
107
- domVisitors: { onElement },
111
+ domVisitors,
108
112
  };
109
113
 
110
114
  return (
@@ -0,0 +1,70 @@
1
+ import React from 'react';
2
+ import {
3
+ useComputeMaxWidthForTag,
4
+ useContentWidth,
5
+ } from 'react-native-render-html';
6
+ import WebView from 'react-native-webview';
7
+ import { findOne } from 'domutils';
8
+ import PropTypes from 'prop-types';
9
+
10
+ function findSource(tnode) {
11
+ if (tnode.attributes.src) {
12
+ return tnode.attributes.src;
13
+ }
14
+
15
+ const sourceElms = findOne(
16
+ elm => elm.tagName === 'source',
17
+ tnode.domNode.children,
18
+ );
19
+
20
+ return sourceElms ? sourceElms.attribs.src : '';
21
+ }
22
+
23
+ /**
24
+ *
25
+ * Generate video html with only selected attributes and parameters.
26
+ * @returns HTML video element
27
+ */
28
+ function generateVideoHtml(tnode) {
29
+ const url = findSource(tnode);
30
+
31
+ const containsTimeParameter = url.match(/(#|\?)t=[^&$]*/g, '');
32
+ // If video has no time parameter, we want to add time parameter at 0.1, just to be able to
33
+ // display the image, first frame of the video. Video tags that don't have autoplay attribute
34
+ // are not showing first frame without this solution.
35
+ // Otherwise, if user has defined time parameter, keep it as is.
36
+ const resolvedUrl = `${url}${containsTimeParameter ? '' : '#t=0.1'}`;
37
+
38
+ return `<video controls src="${resolvedUrl}" style="width: 100%; height: 100%;"/>`;
39
+ }
40
+
41
+ export const VideoRenderer = ({ tnode, style }) => {
42
+ const computeMaxWidth = useComputeMaxWidthForTag('video');
43
+ const width = computeMaxWidth(useContentWidth());
44
+
45
+ // Using uri as a Webview source is not an option, because we don't have as much control of video.
46
+ // E.g. if video from uri has autoplay=true, we can't prevent it from auto-playing when Webview renders.
47
+ // Instead, create video HTML element with only picked attributes and parameters.
48
+ const html = generateVideoHtml(tnode);
49
+
50
+ return (
51
+ <WebView
52
+ scrollEnabled={false}
53
+ source={{
54
+ html,
55
+ }}
56
+ style={[{ aspectRatio: 16 / 9 }, style, { width }]}
57
+ />
58
+ );
59
+ };
60
+
61
+ VideoRenderer.propTypes = {
62
+ tnode: PropTypes.object.isRequired,
63
+ style: PropTypes.object,
64
+ };
65
+
66
+ VideoRenderer.defaultProps = {
67
+ style: {},
68
+ };
69
+
70
+ export default VideoRenderer;
@@ -1,16 +1,19 @@
1
1
  import _ from 'lodash';
2
2
 
3
- // Shoutem RTE component wraps any video attachment (hosted inside iframe) with <figure>
3
+ // Shoutem RTE component wraps any video attachment (hosted inside iframe or video) with <figure>
4
4
  // element. That element contains style that breaks the SimpleHtml UI - enormous blank
5
5
  // space below attachment.
6
6
  // This function removes height and padding-bottom styles from figure to fix this UI issue.
7
7
  export const removeShoutemRteVideoAttachmentWrapper = element => {
8
8
  if (
9
- element.name === 'figure' &&
9
+ (element.name === 'figure' || element.name === 'video') &&
10
10
  element.children.length > 0 &&
11
11
  // <figure> can have multiple generated children too - type:text. Probably caused by empty space between
12
12
  // figure and iframe elements in generated HTML.
13
- _.some(element.children, ({ name }) => name === 'iframe')
13
+ _.some(
14
+ element.children,
15
+ ({ name }) => name === 'iframe' || name === 'video',
16
+ )
14
17
  ) {
15
18
  // Remove height and padding-bottom styles because they break the UI
16
19
  element.attribs.style = element.attribs.style
@@ -0,0 +1,7 @@
1
+ import { HTMLContentModel, HTMLElementModel } from 'react-native-render-html';
2
+
3
+ export const videoModel = HTMLElementModel.fromCustomModel({
4
+ contentModel: HTMLContentModel.block,
5
+ tagName: 'video',
6
+ isOpaque: true,
7
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shoutem/ui",
3
- "version": "6.3.2",
3
+ "version": "6.3.3-rc.0",
4
4
  "description": "Styleable set of components for React Native applications",
5
5
  "scripts": {
6
6
  "lint": "eslint .",