diff --git a/react/features/base/media/components/AbstractAudio.js b/react/features/base/media/components/AbstractAudio.js
new file mode 100644
index 000000000..a2c19a397
--- /dev/null
+++ b/react/features/base/media/components/AbstractAudio.js
@@ -0,0 +1,111 @@
+import React, { Component } from 'react';
+
+/**
+ * The React {@link Component} which is similar to Web's
+ * {@code HTMLAudioElement}.
+ */
+export default class AbstractAudio extends Component {
+ /**
+ * The (reference to the) {@link ReactElement} which actually implements
+ * this {@code AbstractAudio}.
+ */
+ _ref: ?Object
+
+ /**
+ * {@code AbstractAudio} component's property types.
+ *
+ * @static
+ */
+ static propTypes = {
+ /**
+ * The URL of a media resource to use in the element.
+ *
+ * @type {string}
+ */
+ src: React.PropTypes.string,
+ stream: React.PropTypes.object
+ };
+
+ /**
+ * Initializes a new {@code AbstractAudio} instance.
+ *
+ * @param {Object} props - The read-only properties with which the new
+ * instance is to be initialized.
+ */
+ constructor(props) {
+ super(props);
+
+ // Bind event handlers so they are only bound once for every instance.
+ this._setRef = this._setRef.bind(this);
+ }
+
+ /**
+ * Attempts to pause the playback of the media.
+ *
+ * @public
+ * @returns {void}
+ */
+ pause() {
+ this._ref && typeof this._ref.pause === 'function' && this._ref.pause();
+ }
+
+ /**
+ * Attempts to being the playback of the media.
+ *
+ * @public
+ * @returns {void}
+ */
+ play() {
+ this._ref && typeof this._ref.play === 'function' && this._ref.play();
+ }
+
+ /**
+ * Renders this {@code AbstractAudio} as a React {@link Component} of a
+ * specific type.
+ *
+ * @param {string|ReactClass} type - The type of the React {@code Component}
+ * which is to be rendered.
+ * @param {Object|undefined} props - The read-only React {@code Component}
+ * properties, if any, to render. If {@code undefined}, the props of this
+ * instance will be rendered.
+ * @protected
+ * @returns {ReactElement}
+ */
+ _render(type, props) {
+ const {
+ children,
+
+ /* eslint-disable no-unused-vars */
+
+ // The following properties are consumed by React itself so they are
+ // to not be propagated.
+ ref,
+
+ /* eslint-enable no-unused-vars */
+
+ ...filteredProps
+ } = props || this.props;
+
+ return (
+ React.createElement(
+ type,
+ {
+ ...filteredProps,
+ ref: this._setRef
+ },
+ children));
+ }
+
+ /**
+ * Set the (reference to the) {@link ReactElement} which actually implements
+ * this {@code AbstractAudio}.
+ *
+ * @param {Object} ref - The (reference to the) {@code ReactElement} which
+ * actually implements this {@code AbstractAudio}.
+ * @private
+ * @returns {void}
+ */
+ _setRef(ref) {
+ this._ref = ref;
+ }
+}
diff --git a/react/features/base/media/components/AbstractVideoTrack.js b/react/features/base/media/components/AbstractVideoTrack.js
index d15cded48..4c7bbe25b 100644
--- a/react/features/base/media/components/AbstractVideoTrack.js
+++ b/react/features/base/media/components/AbstractVideoTrack.js
@@ -6,11 +6,12 @@ import { shouldRenderVideoTrack } from '../functions';
import { Video } from './_';
/**
- * Component that renders video element for a specified video track.
+ * Implements a React {@link Component} that renders video element for a
+ * specific video track.
*
* @abstract
*/
-export class AbstractVideoTrack extends Component {
+export default class AbstractVideoTrack extends Component {
/**
* AbstractVideoTrack component's property types.
*
diff --git a/react/features/base/media/components/_.web.js b/react/features/base/media/components/_.web.js
index e69de29bb..b80c83af3 100644
--- a/react/features/base/media/components/_.web.js
+++ b/react/features/base/media/components/_.web.js
@@ -0,0 +1 @@
+export * from './web';
diff --git a/react/features/base/media/components/native/Audio.js b/react/features/base/media/components/native/Audio.js
index 82d9cfad1..6335b8d7f 100644
--- a/react/features/base/media/components/native/Audio.js
+++ b/react/features/base/media/components/native/Audio.js
@@ -1,19 +1,19 @@
-import React, { Component } from 'react';
+/* @flow */
+
+import AbstractAudio from '../AbstractAudio';
/**
- * The React Native component which is similar to Web's audio element and wraps
- * around react-native-webrtc's RTCView.
+ * The React Native/mobile {@link Component} which is similar to Web's
+ * {@code HTMLAudioElement} and wraps around react-native-webrtc's
+ * {@link RTCView}.
*/
-export class Audio extends Component {
+export default class Audio extends AbstractAudio {
/**
- * Audio component's property types.
+ * {@code Audio} component's property types.
*
* @static
*/
- static propTypes = {
- muted: React.PropTypes.bool,
- stream: React.PropTypes.object
- };
+ static propTypes = AbstractAudio.propTypes;
/**
* Implements React's {@link Component#render()}.
diff --git a/react/features/base/media/components/native/Video.js b/react/features/base/media/components/native/Video.js
index a19dd570b..471de3223 100644
--- a/react/features/base/media/components/native/Video.js
+++ b/react/features/base/media/components/native/Video.js
@@ -1,21 +1,23 @@
+/* @flow */
+
import React, { Component } from 'react';
import { RTCView } from 'react-native-webrtc';
import { styles } from './styles';
/**
- * The React Native component which is similar to Web's video element and wraps
- * around react-native-webrtc's RTCView.
+ * The React Native {@link Component} which is similar to Web's
+ * {@code HTMLVideoElement} and wraps around react-native-webrtc's
+ * {@link RTCView}.
*/
-export class Video extends Component {
+export default class Video extends Component {
/**
- * Video component's property types.
+ * {@code Video} component's property types.
*
* @static
*/
static propTypes = {
mirror: React.PropTypes.bool,
- muted: React.PropTypes.bool,
onPlaying: React.PropTypes.func,
stream: React.PropTypes.object,
diff --git a/react/features/base/media/components/native/VideoTrack.js b/react/features/base/media/components/native/VideoTrack.js
index 444b9d053..a5ad3dd3f 100644
--- a/react/features/base/media/components/native/VideoTrack.js
+++ b/react/features/base/media/components/native/VideoTrack.js
@@ -2,7 +2,7 @@ import React from 'react';
import { Animated } from 'react-native';
import { connect } from 'react-redux';
-import { AbstractVideoTrack } from '../AbstractVideoTrack';
+import AbstractVideoTrack from '../AbstractVideoTrack';
import { styles } from './styles';
/**
diff --git a/react/features/base/media/components/native/index.js b/react/features/base/media/components/native/index.js
index 50258385e..bb4237197 100644
--- a/react/features/base/media/components/native/index.js
+++ b/react/features/base/media/components/native/index.js
@@ -1,3 +1,3 @@
-export * from './Audio';
-export * from './Video';
+export { default as Audio } from './Audio';
+export { default as Video } from './Video';
export { default as VideoTrack } from './VideoTrack';
diff --git a/react/features/base/media/components/web/Audio.js b/react/features/base/media/components/web/Audio.js
new file mode 100644
index 000000000..22b58b381
--- /dev/null
+++ b/react/features/base/media/components/web/Audio.js
@@ -0,0 +1,26 @@
+/* @flow */
+
+import AbstractAudio from '../AbstractAudio';
+
+/**
+ * The React/Web {@link Component} which is similar to and wraps around
+ * {@code HTMLAudioElement} in order to facilitate cross-platform source code.
+ */
+export default class Audio extends AbstractAudio {
+ /**
+ * {@code Audio} component's property types.
+ *
+ * @static
+ */
+ static propTypes = AbstractAudio.propTypes;
+
+ /**
+ * Implements React's {@link Component#render()}.
+ *
+ * @inheritdoc
+ * @returns {ReactElement}
+ */
+ render() {
+ return super._render('audio');
+ }
+}
diff --git a/react/features/base/media/components/web/index.js b/react/features/base/media/components/web/index.js
new file mode 100644
index 000000000..528c1e495
--- /dev/null
+++ b/react/features/base/media/components/web/index.js
@@ -0,0 +1 @@
+export { default as Audio } from './Audio';
diff --git a/react/features/base/participants/components/Avatar.native.js b/react/features/base/participants/components/Avatar.native.js
index b0bdcde9d..3c10b9c54 100644
--- a/react/features/base/participants/components/Avatar.native.js
+++ b/react/features/base/participants/components/Avatar.native.js
@@ -2,7 +2,7 @@ import React, { Component } from 'react';
import { Image } from 'react-native';
/**
- * Display a participant avatar.
+ * Implements an avatar as a React Native/mobile {@link Component}.
*/
export default class Avatar extends Component {
/**
@@ -12,10 +12,16 @@ export default class Avatar extends Component {
*/
static propTypes = {
/**
- * The optional style to add to an Avatar in order to customize its base
- * look (and feel).
+ * The optional style to add to the {@link Avatar} in order to customize
+ * its base look (and feel).
*/
style: React.PropTypes.object,
+
+ /**
+ * The URI of the {@link Avatar}.
+ *
+ * @type {string}
+ */
uri: React.PropTypes.string
};
@@ -87,13 +93,19 @@ export default class Avatar extends Component {
* @inheritdoc
*/
render() {
+ // Propagate all props of this Avatar but the ones consumed by this
+ // Avatar to the Image it renders.
+
+ // eslint-disable-next-line no-unused-vars
+ const { uri, ...props } = this.props;
+
return (
+ source = { this.state.source } />
);
}
}
diff --git a/react/features/base/participants/components/Avatar.web.js b/react/features/base/participants/components/Avatar.web.js
index 87caa5105..9dd038cc0 100644
--- a/react/features/base/participants/components/Avatar.web.js
+++ b/react/features/base/participants/components/Avatar.web.js
@@ -1,7 +1,7 @@
import React, { Component } from 'react';
/**
- * Display a participant avatar.
+ * Implements an avatar as a React/Web {@link Component}.
*/
export default class Avatar extends Component {
/**
@@ -11,7 +11,7 @@ export default class Avatar extends Component {
*/
static propTypes = {
/**
- * The URL for the avatar.
+ * The URI of the {@link Avatar}.
*
* @type {string}
*/
@@ -24,6 +24,16 @@ export default class Avatar extends Component {
* @inheritdoc
*/
render() {
- return ;
+ // Propagate all props of this Avatar but the ones consumed by this
+ // Avatar to the img it renders.
+
+ // eslint-disable-next-line no-unused-vars
+ const { uri, ...props } = this.props;
+
+ return (
+
+ );
}
}
diff --git a/react/features/base/react/components/AbstractContainer.js b/react/features/base/react/components/AbstractContainer.js
index 8a4f1d6ea..9bddb2d27 100644
--- a/react/features/base/react/components/AbstractContainer.js
+++ b/react/features/base/react/components/AbstractContainer.js
@@ -69,6 +69,11 @@ export default class AbstractContainer extends Component {
...filteredProps
} = props || this.props;
+ // visible
+ if (typeof visible !== 'undefined' && !visible) {
+ return null;
+ }
+
return React.createElement(type, filteredProps, children);
}
}
diff --git a/react/features/base/react/components/Container.native.js b/react/features/base/react/components/Container.native.js
deleted file mode 100644
index 1e1557156..000000000
--- a/react/features/base/react/components/Container.native.js
+++ /dev/null
@@ -1,58 +0,0 @@
-import React from 'react';
-import {
- TouchableHighlight,
- TouchableWithoutFeedback,
- View
-} from 'react-native';
-
-import AbstractContainer from './AbstractContainer';
-
-/**
- * Represents a container of React Native Component children with a style.
- *
- * @extends AbstractContainer
- */
-export class Container extends AbstractContainer {
- /**
- * Container component's property types.
- *
- * @static
- */
- static propTypes = AbstractContainer.propTypes
-
- /**
- * Implements React's {@link Component#render()}.
- *
- * @inheritdoc
- * @returns {ReactElement}
- */
- render() {
- // eslint-disable-next-line prefer-const
- let { onClick, style, touchFeedback, visible, ...props } = this.props;
-
- // visible
- if (typeof visible !== 'undefined' && !visible) {
- return null;
- }
-
- // onClick & touchFeedback
- (typeof touchFeedback === 'undefined') && (touchFeedback = onClick);
-
- const renderParent = touchFeedback || onClick;
-
- // eslint-disable-next-line object-property-newline
- let component = this._render(View, { ...props, style });
-
- if (renderParent) {
- const parentType
- = touchFeedback ? TouchableHighlight : TouchableWithoutFeedback;
- const parentProps = {};
-
- onClick && (parentProps.onPress = onClick);
-
- component = React.createElement(parentType, parentProps, component);
- }
-
- return component;
- }
-}
diff --git a/react/features/base/react/components/Container.web.js b/react/features/base/react/components/Container.web.js
deleted file mode 100644
index e69de29bb..000000000
diff --git a/react/features/base/react/components/Link.web.js b/react/features/base/react/components/Link.web.js
deleted file mode 100644
index e69de29bb..000000000
diff --git a/react/features/base/react/components/Watermarks.native.js b/react/features/base/react/components/Watermarks.native.js
deleted file mode 100644
index e69de29bb..000000000
diff --git a/react/features/base/react/components/_.native.js b/react/features/base/react/components/_.native.js
new file mode 100644
index 000000000..738c4d2b8
--- /dev/null
+++ b/react/features/base/react/components/_.native.js
@@ -0,0 +1 @@
+export * from './native';
diff --git a/react/features/base/react/components/_.web.js b/react/features/base/react/components/_.web.js
new file mode 100644
index 000000000..b80c83af3
--- /dev/null
+++ b/react/features/base/react/components/_.web.js
@@ -0,0 +1 @@
+export * from './web';
diff --git a/react/features/base/react/components/index.js b/react/features/base/react/components/index.js
index 06bf02ab3..cda61441e 100644
--- a/react/features/base/react/components/index.js
+++ b/react/features/base/react/components/index.js
@@ -1,3 +1 @@
-export * from './Container';
-export * from './Link';
-export { default as Watermarks } from './Watermarks';
+export * from './_';
diff --git a/react/features/base/react/components/native/Container.js b/react/features/base/react/components/native/Container.js
new file mode 100644
index 000000000..1c9f33d20
--- /dev/null
+++ b/react/features/base/react/components/native/Container.js
@@ -0,0 +1,55 @@
+import React from 'react';
+import {
+ TouchableHighlight,
+ TouchableWithoutFeedback,
+ View
+} from 'react-native';
+
+import AbstractContainer from '../AbstractContainer';
+
+/**
+ * Represents a container of React Native/mobile {@link Component} children.
+ *
+ * @extends AbstractContainer
+ */
+export default class Container extends AbstractContainer {
+ /**
+ * {@code Container} component's property types.
+ *
+ * @static
+ */
+ static propTypes = AbstractContainer.propTypes;
+
+ /**
+ * Implements React's {@link Component#render()}.
+ *
+ * @inheritdoc
+ * @returns {ReactElement}
+ */
+ render() {
+ // eslint-disable-next-line prefer-const
+ let { onClick, style, touchFeedback, ...props } = this.props;
+
+ // eslint-disable-next-line object-property-newline
+ let component = this._render(View, { ...props, style });
+
+ if (component) {
+ // onClick & touchFeedback
+ (typeof touchFeedback === 'undefined') && (touchFeedback = onClick);
+ if (touchFeedback || onClick) {
+ const parentType
+ = touchFeedback
+ ? TouchableHighlight
+ : TouchableWithoutFeedback;
+ const parentProps = {};
+
+ onClick && (parentProps.onPress = onClick);
+
+ component
+ = React.createElement(parentType, parentProps, component);
+ }
+ }
+
+ return component;
+ }
+}
diff --git a/react/features/base/react/components/Link.native.js b/react/features/base/react/components/native/Link.js
similarity index 90%
rename from react/features/base/react/components/Link.native.js
rename to react/features/base/react/components/native/Link.js
index 39006b1a5..521c92fcf 100644
--- a/react/features/base/react/components/Link.native.js
+++ b/react/features/base/react/components/native/Link.js
@@ -1,13 +1,15 @@
import React, { Component } from 'react';
-import { Linking, Text } from 'react-native';
+import { Linking } from 'react-native';
+
+import Text from './Text';
/**
* Implements a (hyper)link to a URL in the fashion of the HTML anchor element
* and its href attribute.
*/
-export class Link extends Component {
+export default class Link extends Component {
/**
- * Link component's property types.
+ * {@code Link} component's property types.
*
* @static
*/
@@ -56,9 +58,7 @@ export class Link extends Component {
- {
- this.props.children
- }
+ { this.props.children }
);
}
diff --git a/react/features/base/react/components/native/Text.js b/react/features/base/react/components/native/Text.js
new file mode 100644
index 000000000..2fc0f070c
--- /dev/null
+++ b/react/features/base/react/components/native/Text.js
@@ -0,0 +1 @@
+export { Text as default } from 'react-native';
diff --git a/react/features/base/react/components/native/index.js b/react/features/base/react/components/native/index.js
new file mode 100644
index 000000000..42d7e8783
--- /dev/null
+++ b/react/features/base/react/components/native/index.js
@@ -0,0 +1,3 @@
+export { default as Container } from './Container';
+export { default as Link } from './Link';
+export { default as Text } from './Text';
diff --git a/react/features/base/react/components/web/Container.js b/react/features/base/react/components/web/Container.js
new file mode 100644
index 000000000..d2d603597
--- /dev/null
+++ b/react/features/base/react/components/web/Container.js
@@ -0,0 +1,25 @@
+import AbstractContainer from '../AbstractContainer';
+
+/**
+ * Represents a container of React/Web {@link Component} children with a style.
+ *
+ * @extends AbstractContainer
+ */
+export default class Container extends AbstractContainer {
+ /**
+ * {@code Container} component's property types.
+ *
+ * @static
+ */
+ static propTypes = AbstractContainer.propTypes;
+
+ /**
+ * Implements React's {@link Component#render()}.
+ *
+ * @inheritdoc
+ * @returns {ReactElement}
+ */
+ render() {
+ return this._render('div');
+ }
+}
diff --git a/react/features/base/react/components/web/Text.js b/react/features/base/react/components/web/Text.js
new file mode 100644
index 000000000..1a492531d
--- /dev/null
+++ b/react/features/base/react/components/web/Text.js
@@ -0,0 +1,19 @@
+import React, { Component } from 'react';
+
+/**
+ * Implements a React/Web {@link Component} for displaying text similar to React
+ * Native's {@code Text} in order to faciliate cross-platform source code.
+ *
+ * @extends Component
+ */
+export default class Text extends Component {
+ /**
+ * Implements React's {@link Component#render()}.
+ *
+ * @inheritdoc
+ * @returns {ReactElement}
+ */
+ render() {
+ return React.createElement('p', this.props);
+ }
+}
diff --git a/react/features/base/react/components/Watermarks.web.js b/react/features/base/react/components/web/Watermarks.js
similarity index 99%
rename from react/features/base/react/components/Watermarks.web.js
rename to react/features/base/react/components/web/Watermarks.js
index 9da8c27f0..c133da929 100644
--- a/react/features/base/react/components/Watermarks.web.js
+++ b/react/features/base/react/components/web/Watermarks.js
@@ -3,7 +3,7 @@
import React, { Component } from 'react';
import { connect } from 'react-redux';
-import { translate } from '../../i18n';
+import { translate } from '../../../i18n';
declare var interfaceConfig: Object;
diff --git a/react/features/base/react/components/web/index.js b/react/features/base/react/components/web/index.js
new file mode 100644
index 000000000..e7b01210d
--- /dev/null
+++ b/react/features/base/react/components/web/index.js
@@ -0,0 +1,3 @@
+export { default as Container } from './Container';
+export { default as Text } from './Text';
+export { default as Watermarks } from './Watermarks';
diff --git a/react/features/welcome/components/WelcomePage.native.js b/react/features/welcome/components/WelcomePage.native.js
index 8a37dca8d..2da8c9db8 100644
--- a/react/features/welcome/components/WelcomePage.native.js
+++ b/react/features/welcome/components/WelcomePage.native.js
@@ -1,9 +1,9 @@
import React from 'react';
-import { Text, TextInput, TouchableHighlight, View } from 'react-native';
+import { TextInput, TouchableHighlight, View } from 'react-native';
import { connect } from 'react-redux';
import { translate } from '../../base/i18n';
-import { Link } from '../../base/react';
+import { Link, Text } from '../../base/react';
import { ColorPalette } from '../../base/styles';
import { AbstractWelcomePage, _mapStateToProps } from './AbstractWelcomePage';