UNPKG

citong-react-component

Version:

> A component framework for React Native / React Web.

638 lines (574 loc) 19.1 kB
'use strict'; /** * Copyright (c) 2016 Copyright citongs All Rights Reserved. * Author: lipengxiang */ import React, { Component, PropTypes } from 'react'; import ReactNative, { AppRegistry, StyleSheet, Text, View, Image, Platform, TouchableOpacity, } from 'react-native'; import path from 'path'; import { match } from 'react-router'; import {styles, NAV_BAR_HEIGHT, STATUS_BAR_HEIGHT} from './navigator.style'; import {getIconArrowLeft} from './icons'; var NaviRN = ReactNative.Navigator; var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; /** * @desc: NavbarButton */ class NavbarButton extends Component { render() { const { style, tintColor, text, autoBack } = this.props; let backRender; if (autoBack) { backRender = (getIconArrowLeft({tintColor:tintColor, marginRight: 5})); } return ( <View style={[styles.debug, styles.navBarButton, style]}> {backRender}<Text numberOfLines={1} lineBreakMode='tail' style={[styles.navBarButtonText, { color: tintColor }, ]}>{text}</Text> </View> ); } } NavbarButton.propTypes = { style: PropTypes.oneOfType([ PropTypes.object, PropTypes.array, ]), tintColor: PropTypes.string, text: PropTypes.string, onPress: PropTypes.func, autoBack: PropTypes.bool }; NavbarButton.defaultProps = { style: {}, text: '', tintColor: '#0076FF', }; function getButtonElement(data, btn, style, textAuto, defaultBarLeftButtonTextAuto, hasBack, onPress) { const sty = (btn?btn.style:null) || (data?data.style:null); const tintColor = (((btn?btn.tintColor:null) || (data?data.tintColor:null))) || NavbarButton.defaultProps.tintColor; let autoBack = false; let text = (btn?btn.text:null); if (defaultBarLeftButtonTextAuto && text==null) { text = textAuto; autoBack = (hasBack) ? true : false; } else { text = text||(data?data.text:null); } const d = btn ? ((!!btn.props)?btn:null) : (data?((!!data.props)?data:null):null); return ( <TouchableOpacity onPress={onPress}> <View style={[styles.debug, styles.navBarButtonContainer]}> {(d) ? (d) : ( <NavbarButton autoBack={autoBack} text={text} style={[styles.debug, sty, style, ]} tintColor={tintColor} /> )} </View> </TouchableOpacity> ); } function getTitleElement(data, barTitle) { const d = barTitle ? ((!!barTitle.props)?barTitle:null) : ((!!data.props)?data:null); if (d) { return <View style={[styles.debug, styles.customTitle]}>{d}</View>; } const tt = (barTitle?barTitle.text:null) || data.text; const sty = (barTitle?barTitle.style:null) || data.style; const tintColor = ((barTitle?barTitle.tintColor:null) || data.tintColor); const tintColors = tintColor ? {color:tintColor} : null; return ( <View style={[styles.debug, styles.navBarTitleContainer]}> <Text numberOfLines={1} lineBreakMode='tail' style={[styles.debug, styles.navBarTitleText, tintColors, sty ]}> {tt} </Text> </View> ); } //-------------------------------------------------------- // @desc: Router //-------------------------------------------------------- function getRouteInfos(obj, rootPath) { let pp = rootPath?path.join(rootPath, obj.props.path):obj.props.path; let o = { path:pp, component:obj.props.component, barTitle: obj.props.barTitle, barLeftButton: obj.props.barLeftButton, barRightButton: obj.props.barRightButton, barTintColor: obj.props.barTintColor, barHidden: obj.props.barHidden, translucent: obj.props.translucent, configureScene: obj.props.configureScene, childRoutes:[] }; if (obj.props.children) { if (obj.props.children instanceof Array) obj.props.children.forEach(function(element) { o.childRoutes.push(getRouteInfos(element, pp)); }); else o.childRoutes.push(getRouteInfos(obj.props.children, pp)); } return o; } export class Route extends Component { } //-------------------------------------------------------- // @desc: navigator //-------------------------------------------------------- class Navigator extends Component { //this._willNavHidden; constructor(props) { super(props); this._props = props; this._getNavBarRender = this._getNavBarRender.bind(this); this._getCurNavHidden = this._getCurNavHidden.bind(this); this._getCurRoute = this._getCurRoute.bind(this); this._routes = getRouteInfos(this._props.children); // get initialRoute let ctx = this; match({location:'/', routes:this._routes}, (err, redirectLocation, renderProps)=>{ if (renderProps) { ctx._initialRoute = renderProps.routes.length > 0 ? renderProps.routes[renderProps.routes.length-1] : null; ctx._initialRoute = _extends({}, ctx._initialRoute, {params:renderProps.params}); } }); this._bindMethod(this); } _bindMethod(ctx) { Object.defineProperty(Navigator,"navigationBarHeight", { get: function () {return ctx.navigationBarHeight;}, set: function (x) { ctx.navigationBarHeight = x; } }); Object.defineProperty(Navigator,"navigationBarHidden", { get: function () {return ctx.navigationBarHidden;}, set: function (x) { ctx.navigationBarHidden = x; } }); Object.defineProperty(Navigator,"barTintColor", { get: function () {return ctx.barTintColor;}, set: function (x) { ctx.barTintColor = x; } }); Object.defineProperty(Navigator,"onDidFocus", { get: function () {return ctx.onDidFocus;}, set: function (x) { ctx.onDidFocus = x; } }); Object.defineProperty(Navigator,"onLeftButtonPress", { get: function () {return ctx.onLeftButtonPress;}, set: function (x) { ctx.onLeftButtonPress = x; } }); Object.defineProperty(Navigator,"onRightButtonPress", { get: function () {return ctx.onRightButtonPress;}, set: function (x) { ctx.onRightButtonPress = x; } }); Navigator.push = ctx.push.bind(ctx); Navigator.replace = ctx.replace.bind(ctx); Navigator.replacePrevious = ctx.replacePrevious.bind(ctx); Navigator.pop = ctx.pop.bind(ctx); Navigator.popToTop = ctx.popToTop.bind(ctx); Navigator.popToRoute = ctx.popToRoute.bind(ctx); Navigator.resetTo = ctx.resetTo.bind(ctx); } componentDidMount() { // this.push(this.props.initialRoute); // this.setState({navigationBarHidden:this.props.navigationBarHidden}); } componentWillMount() { this.setState({navigationBarHidden:this._props.navigationBarHidden}); if (Platform.OS == 'android') { this._androidListenter = ReactNative.BackAndroid.addEventListener('hardwareBackPress', () => { if (this.refs.nav && this.refs.nav.getCurrentRoutes().length > 1) { this.pop(); return true; } if (!this.refs.nav) return true; return false; }); } } componentWillUnmount() { if (Platform.OS == 'android') { this._androidListenter.remove(); } } /** * @desc: * @return: */ get navigationBarHeight() { return NAV_BAR_HEIGHT; } set navigationBarHeight(h) { console.log('can\'t set navigation bar height'); } /** * @desc: navigationBarHidden */ set navigationBarHidden(r) { this.setState({navigationBarHidden:r}); } get navigationBarHidden() { return this.state&&this.state.navigationBarHidden === true; } /** * @desc: */ set barTintColor(c) { this.setState({barTintColor:c}); } get barTintColor() { return (this.state&&this.state.barTintColor)||(this._props&&this._props.defaultBarTintColor)||'#ffffff'; } /** * @desc: * @return: */ set onDidFocus(c) { var cr = this._getCurRoute(); if (cr) { cr.onDidFocus = c; this.setState({}); } } get onDidFocus() { var cr = this._getCurRoute(); if (cr) { return cr.onDidFocus; } return null; } /** * @desc: * @return: */ set onLeftButtonPress(c) { var cr = this._getCurRoute(); if (cr) { cr.onLeftButtonPress = c; this.setState({}); } } get onLeftButtonPress() { var cr = this._getCurRoute(); if (cr) { return cr.onLeftButtonPress; } return null; } /** * @desc: * @return: */ set onRightButtonPress(c) { var cr = this._getCurRoute(); if (cr) { cr.onRightButtonPress = c; this.setState({}); } } get onRightButtonPress() { var cr = this._getCurRoute(); if (cr) { return cr.onRightButtonPress; } return null; } /** * @desc: push */ push(path, props) { let barHide = this._getCurNavHidden(); // get Route let ctx = this; match({location:path, routes:this._routes}, (err, redirectLocation, renderProps)=>{ if (renderProps) { if (renderProps.routes.length > 0) { let rout = renderProps.routes[renderProps.routes.length-1]; if (props) { rout = _extends({}, rout, props, {params:renderProps.params}); } ctx.refs.nav.push(rout); if (ctx._getCurNavHidden(rout) != barHide) { ctx.setState({}); } } } }); } /** * @desc: replace */ replace(path, props) { let barHide = this._getCurNavHidden(); // get Route let ctx = this; match({location:path, routes:this._routes}, (err, redirectLocation, renderProps)=>{ if (renderProps) { if (renderProps.routes.length > 0) { let rout = renderProps.routes[renderProps.routes.length-1]; if (props) { rout = _extends({}, rout, props, {params:renderProps.params}); } ctx.refs.nav.replace(rout); if (ctx._getCurNavHidden(rout) != barHide) { ctx.setState({}); } } } }); } replacePrevious(path, props) { let barHide = this._getCurNavHidden(); // get Route let ctx = this; match({location:path, routes:this._routes}, (err, redirectLocation, renderProps)=>{ if (renderProps) { if (renderProps.routes.length > 0) { let rout = renderProps.routes[renderProps.routes.length-1]; if (props) { rout = _extends({}, rout, props, {params:renderProps.params}); } ctx.refs.nav.replacePrevious(rout); if (ctx._getCurNavHidden(rout) != barHide) { ctx.setState({}); } } } }); } /** * @desc: back */ pop() { let barHide = this._getCurNavHidden(); this.refs.nav.pop(); if (this._getCurNavHidden() != barHide) { this.setState({}); } } popToTop() { let barHide = this._getCurNavHidden(); this.refs.nav.popToTop(); if (this._getCurNavHidden() != barHide) { this.setState({}); } } popToRoute(path, props) { let barHide = this._getCurNavHidden(); // get Route let ctx = this; match({location:path, routes:this._routes}, (err, redirectLocation, renderProps)=>{ if (renderProps) { if (renderProps.routes.length > 0) { let rout = renderProps.routes[renderProps.routes.length-1]; if (props) { rout = _extends({}, rout, props, {params:renderProps.params}); } ctx.refs.nav.popToRoute(rout); if (ctx._getCurNavHidden(rout) != barHide) { ctx.setState({}); } } } }); } resetTo(path, props) { let barHide = this._getCurNavHidden(); // get Route let ctx = this; match({location:path, routes:this._routes}, (err, redirectLocation, renderProps)=>{ if (renderProps) { if (renderProps.routes.length > 0) { let rout = renderProps.routes[renderProps.routes.length-1]; if (props) { rout = _extends({}, rout, props, {params:renderProps.params}); } ctx.refs.nav.resetTo(rout); if (ctx._getCurNavHidden(rout) != barHide) { ctx.setState({}); } } } }); } _getCurRoute(curRoute) { if (this.refs && this.refs.nav) { let route = curRoute; if (!route) { let routes = this.refs.nav.getCurrentRoutes(); route = routes[routes.length-1]; return route; } return route; } return null; } _getCurNavHidden(curRoute=null) { var has = this.state.navigationBarHidden; if (curRoute && (curRoute.barHidden===true||curRoute.barHidden===false)) { has = curRoute.barHidden; return has; } if (this.refs.nav) { let route = this._getCurRoute(curRoute); if (route && (route.barHidden===true||route.barHidden===false)) { has = route.barHidden; } } return has; } _getNavBarRender() { let has; if (this._willNavHidden === true || this._willNavHidden === false) has = this._willNavHidden; else has = this._getCurNavHidden(); const bar = (has === true) ? null : ( <NaviRN.NavigationBar routeMapper={{ Title: (route, navigator, index, navState) => { return getTitleElement(this.props.defaultBarTitle, route.barTitle); }, LeftButton: (route, navigator, index, navState) => { let text; let hasBack = false; if (this._props.defaultBarLeftButtonTextAuto) { let routes = navigator.getCurrentRoutes(); let ii = routes.indexOf(route); if (ii > 0) { text = routes[ii-1].barTitle; if (text) text = text.text; hasBack = true; } } const btn = route.barLeftButton; let onPress = route.onLeftButtonPress || ( btn ?( btn.onPress || ( this._props.defaultBarLeftButton&&this._props.defaultBarLeftButton.onPress ? this._props.defaultBarLeftButton.onPress : ((navi)=>this.pop()) ) ) :((navi)=>this.pop()) ); return getButtonElement(this._props.defaultBarLeftButton, route.barLeftButton, {marginLeft:8}, text, this.props.defaultBarLeftButtonTextAuto, hasBack, onPress); }, RightButton: (route, navigator, index, navState) => { const btn = route.barRightButton; let onPress = route.onRightButtonPress || (btn?btn.onPress: ( this._props.defaultBarRightButton&&this._props.defaultBarRightButton.onPress ? this._props.defaultBarRightButton.onPress : null ) ); return getButtonElement(this._props.defaultBarRightButton, route.barRightButton, {marginRight:8}, null, null, null, onPress); }, }} style={[styles.debug, styles.navBar, {backgroundColor: this.barTintColor}, {zIndex:1}, styles.split]} /> ); return bar; } render() { const contentOffset = ((this._willNavHidden===true||this._willNavHidden===false) ? this._willNavHidden : this._getCurNavHidden()) ? null : {marginTop: ((Platform.OS == 'ios') ? NAV_BAR_HEIGHT+STATUS_BAR_HEIGHT : NAV_BAR_HEIGHT) }; return ( <NaviRN ref = 'nav' configureScene = {(route, routeStack) => { return (route.configureScene?route.configureScene:this._props.configureScene); } } navigationBar = {this._getNavBarRender()} renderScene = {(route, navigator) => { if (!route.component) return <View/>; return <route.component ref={comp=>this._comp=comp} {...route.passProps}/> }} sceneStyle = {contentOffset} initialRoute = {this._initialRoute} onWillFocus = {(route)=> { this._willNavHidden = this._getCurNavHidden(route); if (this._willNavHidden != this._getCurNavHidden()) {this.setState({});} }} onDidFocus = {(route)=> { route.onDidFocus && route.onDidFocus(route); }} /> ); } } // class Navigator. /** * @desc: * @return: */ const ButtonShape = { text: PropTypes.string, style: PropTypes.object, tintColor: PropTypes.string, onPress: PropTypes.func, }; const TitleShape = { text: PropTypes.string, tintColor: PropTypes.string, style: PropTypes.object, }; Navigator.SceneConfigs = ReactNative.Navigator.SceneConfigs; Navigator.propTypes = { navigationBarHidden: PropTypes.bool, defaultBarTintColor: PropTypes.string, defaultBarLeftButton: PropTypes.oneOfType([ PropTypes.shape(ButtonShape), PropTypes.element, ]), defaultBarRightButton: PropTypes.oneOfType([ PropTypes.shape(ButtonShape), PropTypes.element, ]), defaultBarTitle: PropTypes.oneOfType([ PropTypes.shape(TitleShape), PropTypes.element, ]), }; Navigator.defaultProps = { navigationBarHidden: false, defaultBarTitle: { text: '', }, defaultBarLeftButtonTextAuto: true, configureScene: Navigator.SceneConfigs.FloatFromRight }; //AppRegistry.registerComponent('', () => ); module.exports = Navigator;