[React] Cross-platform Components
Introduce certain React Components which may be used to write cross-platform source code such as Audio like Web's audio, Container like Web's div, Text like Web's p, etc.
This commit is contained in:
parent
d1ea29beeb
commit
409255f056
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
export * from './web';
|
|
@ -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()}.
|
||||
|
|
|
@ -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,
|
||||
|
||||
|
|
|
@ -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';
|
||||
|
||||
/**
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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');
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
export { default as Audio } from './Audio';
|
|
@ -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 (
|
||||
<Image
|
||||
{ ...props }
|
||||
|
||||
// XXX Avatar is expected to display the whole image.
|
||||
resizeMode = 'contain'
|
||||
source = { this.state.source }
|
||||
style = { this.props.style } />
|
||||
source = { this.state.source } />
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 <img src = { this.props.uri } />;
|
||||
// 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 (
|
||||
<img
|
||||
{ ...props }
|
||||
src = { uri } />
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
export * from './native';
|
|
@ -0,0 +1 @@
|
|||
export * from './web';
|
|
@ -1,3 +1 @@
|
|||
export * from './Container';
|
||||
export * from './Link';
|
||||
export { default as Watermarks } from './Watermarks';
|
||||
export * from './_';
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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 {
|
|||
<Text
|
||||
onPress = { this._onPress }
|
||||
style = { this.props.style }>
|
||||
{
|
||||
this.props.children
|
||||
}
|
||||
{ this.props.children }
|
||||
</Text>
|
||||
);
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
export { Text as default } from 'react-native';
|
|
@ -0,0 +1,3 @@
|
|||
export { default as Container } from './Container';
|
||||
export { default as Link } from './Link';
|
||||
export { default as Text } from './Text';
|
|
@ -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');
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
export { default as Container } from './Container';
|
||||
export { default as Text } from './Text';
|
||||
export { default as Watermarks } from './Watermarks';
|
|
@ -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';
|
||||
|
|
Loading…
Reference in New Issue