25 mins
View maps directly to the native view equivalent on whatever platform React Native is running on, whether that is a UIView, <div>, android.view, etc.
https://facebook.github.io/react-native/docs/view.html
Android
iOS
Web
https://microsoft.github.io/reactxp/docs/faq.html
ReactXP builds upon React Native. ReactXP’s components and APIs are inspired by React Native.
import { AppRegistry } from 'react-native';
import App from './App';
AppRegistry.registerComponent('MyApp', () => App);
https://github.com/Microsoft/reactxp/blob/master/samples/hello-world-js/src/index.js
https://github.com/Microsoft/reactxp/blob/master/src/native-common/App.ts
import React from 'react';
import RX from 'reactxp';
import App from './App';
RX.initialize(true, true);
RX.UserInterface(<App />);
import RN from 'react-native';
...
initialize(debug: boolean, development: boolean) {
super.initialize(debug, development);
window['rxdebug'] = debug;
RN.AppRegistry.registerComponent('RXApp', () => RootView);
}
...
API
Props
Styles
Attributes
Animation Interface
Components
Android
iOS
Web
React Native
ReactXP
React Native
ReactXP
Android
iOS
Web
React
Webpack
iOS (React Native)
Android (React Native)
Web (React)
Desktop (Electron)
Chrome
IE (9 and newer)
Edge
Firefox
Safari
Other HTML5 browsers
https://github.com/hinxcode/coscup-schedule-app
https://github.com/Microsoft/reactxp
https://microsoft.github.io/reactxp
Repo
Docs
https://github.com/Microsoft/reactxp/blob/master/src/native-common/ActivityIndicator.tsx
return (
<RN.ActivityIndicator
animating={ this.state.isVisible }
color={ this.state.isVisible ? this.props.color : 'transparent' }
size={ size }
/>
);
const myViewStyle = RX.Styles.createViewStyle({
backgroundColor: '#fff'
});
<RX.View style={myViewStyle} />
/*
{ backgroundColor: '#fff' } <-- ruleSet
*/
createViewStyle(ruleSet: Types.ViewStyle, cacheStyle: boolean = true): Types.ViewStyleRuleSet {
return this._adaptStyles(ruleSet, cacheStyle);
}
https://github.com/Microsoft/reactxp/blob/master/src/native-common/Styles.ts#L71
export interface ViewStyle extends ViewAndImageCommonStyle {
borderStyle?: 'solid' | 'dotted' | 'dashed' | 'none';
...
}
export interface ViewAndImageCommonStyle extends FlexboxStyle, TransformStyle {
borderWidth?: number;
borderColor?: string;
borderRadius?: number;
...
}
export interface FlexboxStyle {
...
}
https://github.com/Microsoft/reactxp/blob/master/src/common/Types.ts
createViewStyle(ruleSet: Types.ViewStyle, cacheStyle: boolean = true): Types.ViewStyleRuleSet {
return this._adaptStyles(ruleSet, cacheStyle);
}
private _adaptStyles<S extends Types.ViewAndImageCommonStyle>(def: S, cacheStyle: boolean): Types.StyleRuleSet<S> {
let adaptedRuleSet = def as ReactNativeViewAndImageCommonStyle<S>;
...
// Convert text styling
let textStyle = adaptedRuleSet as Types.TextStyle;
if (textStyle.font) {
if (textStyle.font.fontFamily !== undefined) {
textStyle.fontFamily = textStyle.font.fontFamily;
}
if (textStyle.font.fontWeight !== undefined) {
textStyle.fontWeight = textStyle.font.fontWeight;
}
if (textStyle.font.fontStyle !== undefined) {
textStyle.fontStyle = textStyle.font.fontStyle;
}
delete textStyle.font;
}
if (def.flex !== undefined) {
var flexValue = def.flex;
delete adaptedRuleSet.flex;
if (flexValue > 0) {
// p 1 auto
adaptedRuleSet.flexGrow = flexValue;
adaptedRuleSet.flexShrink = 1;
} else if (flexValue < 0) {
// 0 -n auto
adaptedRuleSet.flexGrow = 0;
adaptedRuleSet.flexShrink = -flexValue;
} else {
// 0 0 auto
adaptedRuleSet.flexGrow = 0;
adaptedRuleSet.flexShrink = 0;
}
}
...
return adaptedRuleSet;
}
https://github.com/Microsoft/reactxp/blob/master/src/native-common/Styles.ts#L135
let dynamicViewStyle = RX.Styles.createViewStyle({
backgroundColor: userColor
}, false);
createViewStyle(ruleSet: Types.ViewStyle, cacheStyle: boolean = true): Types.ViewStyleRuleSet {
return this._adaptStyles(ruleSet, cacheStyle);
}
constructor(props) {
...
this._translationValue = new RX.Animated.Value(-100);
}
constructor(props) {
...
this._animatedStyle = RX.Styles.createAnimatedTextStyle({
transform: [{
translateY: this._translationValue
}]
});
}
render() {
<RX.Animated.Text style={ this._animatedStyle }>
Hello World
</RX.Animated.Text>
}
constructor(props) {
...
this._translationValue = new RX.Animated.Value(-100);
}
componentDidMount() {
let animation = RX.Animated.timing(this._translationValue, {
toValue: 0,
easing: RX.Animated.Easing.OutBack(),
duration: 500
}
);
animation.start();
}
let compositeAnimation = RX.Animated.parallel([
RX.Animated.timing(animatedScaleValue,
{ toValue: 0.0, duration: 250, easing: RX.Animated.Easing.InOut() }
),
RX.Animated.timing(animatedOpacityValue,
{ toValue: 1.1, duration 250, easing: RX.Animated.Easing.Linear() }
)
]);
compositeAnimation.start();
Sometimes it’s useful to execute multiple animations in parallel or in sequence.
import RN = require('react-native');
...
export var Animated = {
...
delay: RN.Animated.delay,
parallel: RN.Animated.parallel,
sequence: RN.Animated.sequence
};
https://github.com/Microsoft/reactxp/blob/master/src/native-common/Animated.tsx#L194
/* Methods */
initialize(debug: boolean, development: boolean): void;
getActivationState(): AppActivationState;
...
https://microsoft.github.io/reactxp/docs/apis/app.html
import React from 'react';
import RX from 'reactxp';
import App from './App';
RX.App.initialize(true, true);
RX.UserInterface.setMainView(<App />);
/* Methods */
setMainView(element: React.ReactElement<any>): void;
useCustomScrollbars(enable: boolean): void;
isHighPixelDensityScreen(): boolean;
getContentSizeMultiplier(): SyncTasks.Promise<number>;
getMaxContentSizeMultiplier(): SyncTasks.Promise<number>;
setMaxContentSizeMultiplier(maxContentSizeMultiplier: number): void;
dismissKeyboard(): void;
isNavigatingWithKeyboard(): boolean;
...
https://microsoft.github.io/reactxp/docs/apis/userinterface.html
/* Types */
interface SmsInfo {
phoneNumber?: string;
body?: string;
}
interface EmailInfo {
to?: string[];
cc?: string[];
bcc?: string[];
subject?: string;
body?: string;
}
interface LinkingErrorInfo {
code: LinkingError;
url: string;
error?: string;
}
enum LinkingErrorCode {
NoAppFound = 0,
UnexpectedFailure = 1,
Blocked = 2,
InitialUrlNotFound = 3
}
/* Methods */
openUrl(url: string): SyncTasks.Promise<void>;
launchSms(smsData: SmsInfo): SyncTasks.Promise<void>;
launchEmail(emailData: EmailInfo): SyncTasks.Promise<void>;
...
https://microsoft.github.io/reactxp/docs/apis/linking.html
/* Types */
enum DeviceNetworkType {
Unknown,
None,
Wifi,
Mobile2G,
Mobile3G,
Mobile4G
}
/* Methods */
isConnected(): SyncTasks.Promise<boolean>;
getType(): SyncTasks.Promise<DeviceNetworkType>;
/* Events */
connectivityChangedEvent: SubscribableEvent<(isConnected: boolean) => void>;
https://microsoft.github.io/reactxp/docs/apis/network.html
/* Types */
type PlatformType = 'web' | 'ios' | 'android' | 'windows';
/* Methods */
getType(): Types.PlatformType;
https://microsoft.github.io/reactxp/docs/apis/platform.html
/* Methods */
isUserPresent(): boolean;
/* Events */
userPresenceChangedEvent: SubscribableEvent<
(isPresent: boolean) => void>();
https://microsoft.github.io/reactxp/docs/apis/userpresence.html
import RXVideoPlayer from 'reactxp-videoplayer';
class MyVideoPanel extends RX.Component<null, null> {
render() {
return (
<RXVideoPlayer
source={ this.props.source }
showControls={ true }
onProgress={ this._onVideoProgress }
onEnded={ this._onVideoEnded }
/>
);
}
}
Contain no platform-specific code but build upon the lower-level primitives
https://github.com/taobaofed/react-web
https://github.com/lelandrichardson/react-primitives
https://github.com/necolas/react-native-web
https://github.com/react-native-training/create-xp-app
https://www.facebook.com/groups/reactnativetw