diff --git a/Examples/UIExplorer/js/UIExplorerActions.js b/Examples/UIExplorer/js/UIExplorerActions.js
index 8a6b1ee8c08..d1983e90736 100644
--- a/Examples/UIExplorer/js/UIExplorerActions.js
+++ b/Examples/UIExplorer/js/UIExplorerActions.js
@@ -23,22 +23,35 @@
*/
'use strict';
-export type UIExplorerListWithFilterAction = {
- type: 'UIExplorerListWithFilterAction',
- filter: ?string;
+export type UIExplorerBackAction = {
+ type: 'UIExplorerBackAction',
+};
+
+export type UIExplorerListAction = {
+ type: 'UIExplorerListAction',
};
export type UIExplorerExampleAction = {
type: 'UIExplorerExampleAction',
- openExample: string;
+ openExample: string,
};
-export type UIExplorerAction = UIExplorerListWithFilterAction | UIExplorerExampleAction;
+export type UIExplorerAction = (
+ UIExplorerBackAction |
+ UIExplorerListAction |
+ UIExplorerExampleAction
+);
-function ExampleListWithFilter(filter: ?string): UIExplorerListWithFilterAction {
+
+function Back(): UIExplorerBackAction {
return {
- type: 'UIExplorerListWithFilterAction',
- filter,
+ type: 'UIExplorerBackAction',
+ };
+}
+
+function ExampleList(): UIExplorerListAction {
+ return {
+ type: 'UIExplorerListAction',
};
}
@@ -50,7 +63,8 @@ function ExampleAction(openExample: string): UIExplorerExampleAction {
}
const UIExplorerActions = {
- ExampleListWithFilter,
+ Back,
+ ExampleList,
ExampleAction,
};
diff --git a/Examples/UIExplorer/js/UIExplorerApp.android.js b/Examples/UIExplorer/js/UIExplorerApp.android.js
index 35c96cb558c..683f53b1342 100644
--- a/Examples/UIExplorer/js/UIExplorerApp.android.js
+++ b/Examples/UIExplorer/js/UIExplorerApp.android.js
@@ -33,18 +33,18 @@ const React = require('react');
const StatusBar = require('StatusBar');
const StyleSheet = require('StyleSheet');
const ToolbarAndroid = require('ToolbarAndroid');
+const UIExplorerActions = require('./UIExplorerActions');
const UIExplorerExampleContainer = require('./UIExplorerExampleContainer');
const UIExplorerExampleList = require('./UIExplorerExampleList');
const UIExplorerList = require('./UIExplorerList');
const UIExplorerNavigationReducer = require('./UIExplorerNavigationReducer');
-const UIExplorerStateTitleMap = require('./UIExplorerStateTitleMap');
const UIManager = require('UIManager');
const URIActionMap = require('./URIActionMap');
const View = require('View');
const nativeImageSource = require('nativeImageSource');
-import type {UIExplorerNavigationState} from './UIExplorerNavigationReducer';
+import type { UIExplorerNavigationState } from './UIExplorerNavigationReducer';
UIManager.setLayoutAnimationEnabledExperimental(true);
@@ -54,27 +54,31 @@ type Props = {
exampleFromAppetizeParams: string,
};
-type State = UIExplorerNavigationState & {
- externalExample: ?string,
-};
+const APP_STATE_KEY = 'UIExplorerAppState.v2';
+
+const HEADER_LOGO_ICON = nativeImageSource({
+ android: 'launcher_icon',
+ width: 132,
+ height: 144
+});
+
+const HEADER_NAV_ICON = nativeImageSource({
+ android: 'ic_menu_black_24dp',
+ width: 48,
+ height: 48
+});
class UIExplorerApp extends React.Component {
- _handleAction: Function;
- _renderDrawerContent: Function;
- state: State;
- constructor(props: Props) {
- super(props);
- this._handleAction = this._handleAction.bind(this);
- this._renderDrawerContent = this._renderDrawerContent.bind(this);
- }
+ props: Props;
+ state: UIExplorerNavigationState;
componentWillMount() {
- BackAndroid.addEventListener('hardwareBackPress', this._handleBackButtonPress.bind(this));
+ BackAndroid.addEventListener('hardwareBackPress', this._handleBackButtonPress);
}
componentDidMount() {
Linking.getInitialURL().then((url) => {
- AsyncStorage.getItem('UIExplorerAppState', (err, storedString) => {
+ AsyncStorage.getItem(APP_STATE_KEY, (err, storedString) => {
const exampleAction = URIActionMap(this.props.exampleFromAppetizeParams);
const urlAction = URIActionMap(url);
const launchAction = exampleAction || urlAction;
@@ -116,7 +120,7 @@ class UIExplorerApp extends React.Component {
);
}
- _renderDrawerContent() {
+ _renderDrawerContent = () => {
return (
);
- }
+ };
_renderApp() {
const {
- externalExample,
- stack,
+ openExample,
} = this.state;
- if (externalExample) {
- const Component = UIExplorerList.Modules[externalExample];
- return (
- {
- this._handleAction({ type: 'BackAction' });
- }}
- ref={(example) => { this._exampleRef = example; }}
- />
- );
- }
- const title = UIExplorerStateTitleMap(stack.routes[stack.index]);
- const index = stack.routes.length <= 1 ? 1 : stack.index;
- if (stack && stack.routes[index]) {
- const {key} = stack.routes[index];
- const ExampleModule = UIExplorerList.Modules[key];
- if (ExampleModule) {
+ if (openExample) {
+ const ExampleModule = UIExplorerList.Modules[openExample];
+ if (ExampleModule.external) {
+ return (
+ {
+ this._handleAction(UIExplorerActions.Back());
+ }}
+ ref={(example) => { this._exampleRef = example; }}
+ />
+ );
+ } else if (ExampleModule) {
return (
this.drawer.openDrawer()}
style={styles.toolbar}
- title={title}
+ title={ExampleModule.title}
/>
this.drawer.openDrawer()}
style={styles.toolbar}
- title={title}
+ title="UIExplorer"
/>
);
}
- _handleAction(action: Object): boolean {
+ _handleAction = (action: Object): boolean => {
this.drawer && this.drawer.closeDrawer();
const newState = UIExplorerNavigationReducer(this.state, action);
if (this.state !== newState) {
this.setState(
newState,
- () => AsyncStorage.setItem('UIExplorerAppState', JSON.stringify(this.state))
+ () => AsyncStorage.setItem(APP_STATE_KEY, JSON.stringify(this.state))
);
return true;
}
return false;
- }
+ };
- _handleBackButtonPress() {
+ _handleBackButtonPress = () => {
if (this._overrideBackPressForDrawerLayout) {
// This hack is necessary because drawer layout provides an imperative API
// with open and close methods. This code would be cleaner if the drawer
@@ -231,8 +213,8 @@ class UIExplorerApp extends React.Component {
) {
return true;
}
- return this._handleAction({ type: 'BackAction' });
- }
+ return this._handleAction(UIExplorerActions.Back());
+ };
}
const styles = StyleSheet.create({
diff --git a/Examples/UIExplorer/js/UIExplorerApp.ios.js b/Examples/UIExplorer/js/UIExplorerApp.ios.js
index c755f7d76a3..802413c0468 100644
--- a/Examples/UIExplorer/js/UIExplorerApp.ios.js
+++ b/Examples/UIExplorer/js/UIExplorerApp.ios.js
@@ -27,62 +27,46 @@ const AsyncStorage = require('AsyncStorage');
const Linking = require('Linking');
const React = require('react');
const ReactNative = require('react-native');
+const UIExplorerActions = require('./UIExplorerActions');
const UIExplorerExampleContainer = require('./UIExplorerExampleContainer');
const UIExplorerExampleList = require('./UIExplorerExampleList');
const UIExplorerList = require('./UIExplorerList.ios');
const UIExplorerNavigationReducer = require('./UIExplorerNavigationReducer');
-const UIExplorerStateTitleMap = require('./UIExplorerStateTitleMap');
const URIActionMap = require('./URIActionMap');
const {
+ Button,
AppRegistry,
- NavigationExperimental,
SnapshotViewIOS,
StyleSheet,
+ Text,
View,
} = ReactNative;
-const {
- CardStack: NavigationCardStack,
- Header: NavigationHeader,
-} = NavigationExperimental;
-
-import type { NavigationSceneRendererProps } from 'NavigationTypeDefinition';
-
-import type { UIExplorerNavigationState } from './UIExplorerNavigationReducer';
-
import type { UIExplorerExample } from './UIExplorerList.ios';
+import type { UIExplorerAction } from './UIExplorerActions';
+import type { UIExplorerNavigationState } from './UIExplorerNavigationReducer';
type Props = {
exampleFromAppetizeParams: string,
};
-type State = UIExplorerNavigationState & {
- externalExample?: string,
-};
+const APP_STATE_KEY = 'UIExplorerAppState.v2';
-const APP_STATE_KEY = 'UIExplorerAppState.v1';
+const Header = ({ onBack, title}) => (
+
+
+ {title}
+
+ {onBack &&
+
+ }
+
+);
class UIExplorerApp extends React.Component {
- _handleBack: Function;
- _handleAction: Function;
- _renderCard: Function;
- _renderHeader: Function;
- _renderScene: Function;
- _renderTitleComponent: Function;
- state: State;
-
- constructor(props: Props) {
- super(props);
- }
-
- componentWillMount() {
- this._handleAction = this._handleAction.bind(this);
- this._handleBack = this._handleAction.bind(this, {type: 'back'});
- this._renderHeader = this._renderHeader.bind(this);
- this._renderScene = this._renderScene.bind(this);
- this._renderTitleComponent = this._renderTitleComponent.bind(this);
- }
+ props: Props;
+ state: UIExplorerNavigationState;
componentDidMount() {
Linking.getInitialURL().then((url) => {
@@ -92,7 +76,7 @@ class UIExplorerApp extends React.Component {
const launchAction = exampleAction || urlAction;
if (err || !storedString) {
const initialAction = launchAction || {type: 'InitialAction'};
- this.setState(UIExplorerNavigationReducer(null, initialAction));
+ this.setState(UIExplorerNavigationReducer(undefined, initialAction));
return;
}
const storedState = JSON.parse(storedString);
@@ -109,7 +93,11 @@ class UIExplorerApp extends React.Component {
});
}
- _handleAction(action: Object) {
+ _handleBack = () => {
+ this._handleAction(UIExplorerActions.Back());
+ }
+
+ _handleAction = (action: ?UIExplorerAction) => {
if (!action) {
return;
}
@@ -126,73 +114,58 @@ class UIExplorerApp extends React.Component {
if (!this.state) {
return null;
}
- if (this.state.externalExample) {
- const Component = UIExplorerList.Modules[this.state.externalExample];
- return (
- {
- this._handleAction({ type: 'BackAction' });
- }}
- />
- );
+ if (this.state.openExample) {
+ const Component = UIExplorerList.Modules[this.state.openExample];
+ if (Component.external) {
+ return (
+
+ );
+ } else {
+ return (
+
+
+
+
+ );
+ }
+
}
return (
-
- );
- }
-
- _renderHeader(props: NavigationSceneRendererProps): React.Element {
- return (
-
- );
- }
-
- _renderTitleComponent(props: NavigationSceneRendererProps): React.Element {
- return (
-
- {UIExplorerStateTitleMap(props.scene.route)}
-
- );
- }
-
- _renderScene(props: NavigationSceneRendererProps): ?React.Element {
- const state = props.scene.route;
- if (state.key === 'AppList') {
- return (
+
+
- );
- }
-
- const Example = UIExplorerList.Modules[state.key];
- if (Example) {
- return (
-
-
-
- );
- }
- return null;
+
+ );
}
}
const styles = StyleSheet.create({
- container: {
+ header: {
+ height: 60,
+ borderBottomWidth: StyleSheet.hairlineWidth,
+ borderBottomColor: '#96969A',
+ backgroundColor: '#F5F5F6',
+ flexDirection: 'row',
+ paddingTop: 20,
+ },
+ headerLeft: {
+ },
+ headerCenter: {
flex: 1,
+ position: 'absolute',
+ top: 27,
+ left: 0,
+ right: 0,
+ },
+ title: {
+ fontSize: 19,
+ fontWeight: '600',
+ textAlign: 'center',
},
exampleContainer: {
flex: 1,
diff --git a/Examples/UIExplorer/js/UIExplorerExampleList.js b/Examples/UIExplorer/js/UIExplorerExampleList.js
index 72db7e37774..aea6911313c 100644
--- a/Examples/UIExplorer/js/UIExplorerExampleList.js
+++ b/Examples/UIExplorer/js/UIExplorerExampleList.js
@@ -154,9 +154,7 @@ class UIExplorerExampleList extends React.Component {
}}}
onNavigate={this.props.onNavigate}
onPress={() => {
- this.props.onNavigate(
- UIExplorerActions.ExampleListWithFilter('')
- );
+ this.props.onNavigate(UIExplorerActions.ExampleList());
}}
/>
);
diff --git a/Examples/UIExplorer/js/UIExplorerNavigationReducer.js b/Examples/UIExplorer/js/UIExplorerNavigationReducer.js
index 160f7a05bea..015f1e5c2b9 100644
--- a/Examples/UIExplorer/js/UIExplorerNavigationReducer.js
+++ b/Examples/UIExplorer/js/UIExplorerNavigationReducer.js
@@ -23,151 +23,47 @@
*/
'use strict';
-const ReactNative = require('react-native');
// $FlowFixMe : This is a platform-forked component, and flow seems to only run on iOS?
const UIExplorerList = require('./UIExplorerList');
-const {
- NavigationExperimental,
-} = ReactNative;
-
-
-const {
- StateUtils: NavigationStateUtils,
-} = NavigationExperimental;
-
-import type {NavigationState} from 'NavigationTypeDefinition';
-
export type UIExplorerNavigationState = {
- externalExample: ?string;
- stack: NavigationState;
+ openExample: ?string,
};
-const defaultGetReducerForState = (initialState) => (state) => state || initialState;
+function UIExplorerNavigationReducer(
+ state: ?UIExplorerNavigationState,
+ action: any
+): UIExplorerNavigationState {
-function getNavigationState(state: any): ?NavigationState {
if (
- (state instanceof Object) &&
- (state.routes instanceof Array) &&
- (state.routes[0] !== undefined) &&
- (typeof state.index === 'number') &&
- (state.routes[state.index] !== undefined)
+ // Default value is to see example list
+ !state ||
+
+ // Handle the explicit list action
+ action.type === 'UIExplorerListAction' ||
+
+ // Handle requests to go back to the list when an example is open
+ (state.openExample && action.type === 'UIExplorerBackAction')
) {
- return state;
- }
- return null;
-}
-
-function StackReducer({initialState, getReducerForState, getPushedReducerForAction}: any): Function {
- const getReducerForStateWithDefault = getReducerForState || defaultGetReducerForState;
- return function (lastState: ?NavigationState, action: any): NavigationState {
- if (!lastState) {
- return initialState;
- }
- const lastParentState = getNavigationState(lastState);
- if (!lastParentState) {
- return lastState;
- }
-
- const activeSubState = lastParentState.routes[lastParentState.index];
- const activeSubReducer = getReducerForStateWithDefault(activeSubState);
- const nextActiveState = activeSubReducer(activeSubState, action);
- if (nextActiveState !== activeSubState) {
- const nextChildren = [...lastParentState.routes];
- nextChildren[lastParentState.index] = nextActiveState;
- return {
- ...lastParentState,
- routes: nextChildren,
- };
- }
-
- const subReducerToPush = getPushedReducerForAction(action, lastParentState);
- if (subReducerToPush) {
- return NavigationStateUtils.push(
- lastParentState,
- subReducerToPush(null, action)
- );
- }
-
- switch (action.type) {
- case 'back':
- case 'BackAction':
- if (lastParentState.index === 0 || lastParentState.routes.length === 1) {
- return lastParentState;
- }
- return NavigationStateUtils.pop(lastParentState);
- }
-
- return lastParentState;
- };
-}
-
-const UIExplorerStackReducer = StackReducer({
- getPushedReducerForAction: (action, lastState) => {
- if (action.type === 'UIExplorerExampleAction' && UIExplorerList.Modules[action.openExample]) {
- if (lastState.routes.find(route => route.key === action.openExample)) {
- // The example is already open, we should avoid pushing examples twice
- return null;
- }
- return (state) => state || {key: action.openExample};
- }
- return null;
- },
- getReducerForState: (initialState) => (state) => state || initialState,
- initialState: {
- key: 'UIExplorerMainStack',
- index: 0,
- routes: [
- {key: 'AppList'},
- ],
- },
-});
-
-function UIExplorerNavigationReducer(lastState: ?UIExplorerNavigationState, action: any): UIExplorerNavigationState {
- if (!lastState) {
return {
- externalExample: null,
- stack: UIExplorerStackReducer(null, action),
- };
- }
- if (action.type === 'UIExplorerListWithFilterAction') {
- return {
- externalExample: null,
- stack: {
- key: 'UIExplorerMainStack',
- index: 0,
- routes: [
- {
- key: 'AppList',
- filter: action.filter,
- },
- ],
- },
- };
- }
- if (action.type === 'BackAction' && lastState.externalExample) {
- return {
- ...lastState,
- externalExample: null,
+ // A null openExample will cause the views to display the UIExplorer example list
+ openExample: null,
};
}
+
if (action.type === 'UIExplorerExampleAction') {
+
+ // Make sure we see the module before returning the new state
const ExampleModule = UIExplorerList.Modules[action.openExample];
- if (ExampleModule && ExampleModule.external) {
+
+ if (ExampleModule) {
return {
- ...lastState,
- externalExample: action.openExample,
+ openExample: action.openExample,
};
}
}
- const newStack = UIExplorerStackReducer(lastState.stack, action);
- if (newStack !== lastState.stack) {
- return {
- externalExample: null,
- stack: newStack,
- };
- }
- return lastState;
+
+ return state;
}
module.exports = UIExplorerNavigationReducer;
diff --git a/Examples/UIExplorer/js/UIExplorerStateTitleMap.js b/Examples/UIExplorer/js/UIExplorerStateTitleMap.js
deleted file mode 100644
index a1b1d130982..00000000000
--- a/Examples/UIExplorer/js/UIExplorerStateTitleMap.js
+++ /dev/null
@@ -1,41 +0,0 @@
-/**
- * Copyright (c) 2013-present, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * The examples provided by Facebook are for non-commercial testing and
- * evaluation purposes only.
- *
- * Facebook reserves all rights not expressly granted.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL
- * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
- * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- * @flow
- * @providesModule UIExplorerStateTitleMap
- */
-'use strict';
-
-// $FlowFixMe : This is a platform-forked component, and flow seems to only run on iOS?
-const UIExplorerList = require('./UIExplorerList');
-
-import type {NavigationRoute} from 'NavigationTypeDefinition';
-
-function StateTitleMap(route: NavigationRoute): string {
- if (UIExplorerList.Modules[route.key]) {
- return UIExplorerList.Modules[route.key].title;
- }
- if (route.key === 'AppList') {
- return 'UIExplorer';
- }
- return 'Unknown';
-}
-
-module.exports = StateTitleMap;
diff --git a/Examples/UIExplorer/js/URIActionMap.js b/Examples/UIExplorer/js/URIActionMap.js
index 37c0006bde7..fb25f58119c 100644
--- a/Examples/UIExplorer/js/URIActionMap.js
+++ b/Examples/UIExplorer/js/URIActionMap.js
@@ -32,7 +32,9 @@ const {
Alert,
} = ReactNative;
-function PathActionMap(path: string): ?Object {
+import type { UIExplorerAction } from './UIExplorerActions';
+
+function PathActionMap(path: string): ?UIExplorerAction {
// Warning! Hacky parsing for example code. Use a library for this!
const exampleParts = path.split('/example/');
const exampleKey = exampleParts[1];
@@ -46,11 +48,11 @@ function PathActionMap(path: string): ?Object {
return null;
}
-function URIActionMap(uri: ?string): ?Object {
- // Warning! Hacky parsing for example code. Use a library for this!
+function URIActionMap(uri: ?string): ?UIExplorerAction {
if (!uri) {
return null;
}
+ // Warning! Hacky parsing for example code. Use a library for this!
const parts = uri.split('rnuiexplorer:/');
if (!parts[1]) {
return null;