Lin Yiting

Init: Copy from git@github.com:facebookarchive/react-native-custom-components.git

  1 +LICENSE AGREEMENT
  2 +
  3 +For React Native Custom Components software
  4 +
  5 +Copyright (c) 2015, Facebook, Inc. All rights reserved.
  6 +
  7 +Facebook, Inc. (“Facebook”) owns all right, title and interest, including all intellectual property and other proprietary rights, in and to the React Native Custom Components software (the “Software”). Subject to your compliance with these terms, you are hereby granted a non-exclusive, worldwide, royalty-free copyright license to (1) use and copy the Software; and (2) reproduce and distribute the Software as part of your own software (“Your Software”). Facebook reserves all rights not expressly granted to you in this license agreement.
  8 +
  9 +THE SOFTWARE AND DOCUMENTATION, IF ANY, ARE PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES (INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE) ARE DISCLAIMED. IN NO EVENT SHALL FACEBOOK OR ITS AFFILIATES, OFFICERS, DIRECTORS OR EMPLOYEES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  1 +# React Native Legacy Custom Components
  2 +
  3 +This is a module for legacy "CustomComponents" to gracefully deprecate.
  4 +
  5 +## Navigator
  6 +
  7 +The navigator component in this module will behave identically as the one in old version of React native, with one exception:
  8 +
  9 +Latest documentation is available here: http://facebook.github.io/react-native/releases/0.43/docs/navigator.html
  10 +
  11 +
  12 +### Breaking Changes from react-native
  13 +
  14 +- Navigator.props.sceneStyle must be a plain object, not a stylesheet!
  15 +
  16 +(this breaking change is needed to avoid calling React Native's private APIs)
  1 +{
  2 + "name": "react-native-deprecated-custom-components",
  3 + "version": "0.1.1",
  4 + "description": "Deprecated custom components that originally shipped with React Native",
  5 + "repository": {
  6 + "type": "git",
  7 + "url": "git@github.com:facebookarchive/react-native-custom-components.git"
  8 + },
  9 + "main": "src/CustomComponents.js",
  10 + "dependencies": {
  11 + "fbjs": "~0.8.9",
  12 + "immutable": "~3.7.6",
  13 + "create-react-class": "15.6.0",
  14 + "prop-types": "^15.5.10",
  15 + "react-timer-mixin": "^0.13.2",
  16 + "rebound": "^0.0.13"
  17 + },
  18 + "peerDependencies": {
  19 + "react-native": "*"
  20 + }
  21 +}
  1 +/**
  2 + * Copyright (c) 2015, Facebook, Inc. All rights reserved.
  3 + *
  4 + * Facebook, Inc. ("Facebook") owns all right, title and interest, including
  5 + * all intellectual property and other proprietary rights, in and to the React
  6 + * Native CustomComponents software (the "Software"). Subject to your
  7 + * compliance with these terms, you are hereby granted a non-exclusive,
  8 + * worldwide, royalty-free copyright license to (1) use and copy the Software;
  9 + * and (2) reproduce and distribute the Software as part of your own software
  10 + * ("Your Software"). Facebook reserves all rights not expressly granted to
  11 + * you in this license agreement.
  12 + *
  13 + * THE SOFTWARE AND DOCUMENTATION, IF ANY, ARE PROVIDED "AS IS" AND ANY EXPRESS
  14 + * OR IMPLIED WARRANTIES (INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  15 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE) ARE DISCLAIMED.
  16 + * IN NO EVENT SHALL FACEBOOK OR ITS AFFILIATES, OFFICERS, DIRECTORS OR
  17 + * EMPLOYEES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  18 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  19 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  20 + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  21 + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  22 + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE SOFTWARE, EVEN IF
  23 + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  24 + *
  25 + */
  26 +
  27 +
  28 +const Navigator = require('./Navigator');
  29 +
  30 +module.exports = {
  31 + Navigator,
  32 +};
  1 +/**
  2 + * Copyright (c) 2015, Facebook, Inc. All rights reserved.
  3 + *
  4 + * Facebook, Inc. ("Facebook") owns all right, title and interest, including
  5 + * all intellectual property and other proprietary rights, in and to the React
  6 + * Native CustomComponents software (the "Software"). Subject to your
  7 + * compliance with these terms, you are hereby granted a non-exclusive,
  8 + * worldwide, royalty-free copyright license to (1) use and copy the Software;
  9 + * and (2) reproduce and distribute the Software as part of your own software
  10 + * ("Your Software"). Facebook reserves all rights not expressly granted to
  11 + * you in this license agreement.
  12 + *
  13 + * THE SOFTWARE AND DOCUMENTATION, IF ANY, ARE PROVIDED "AS IS" AND ANY EXPRESS
  14 + * OR IMPLIED WARRANTIES (INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  15 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE) ARE DISCLAIMED.
  16 + * IN NO EVENT SHALL FACEBOOK OR ITS AFFILIATES, OFFICERS, DIRECTORS OR
  17 + * EMPLOYEES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  18 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  19 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  20 + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  21 + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  22 + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE SOFTWARE, EVEN IF
  23 + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  24 + *
  25 + * @noflow
  26 + */
  27 +'use strict';
  28 +
  29 +const EventSubscription = require('./EventSubscription');
  30 +
  31 +import type EventEmitter from './EventEmitter';
  32 +import type EventSubscriptionVendor from './EventSubscriptionVendor';
  33 +
  34 +/**
  35 + * EmitterSubscription represents a subscription with listener and context data.
  36 + */
  37 +class EmitterSubscription extends EventSubscription {
  38 +
  39 + emitter: EventEmitter;
  40 + listener: Function;
  41 + context: ?Object;
  42 +
  43 + /**
  44 + * @param {EventEmitter} emitter - The event emitter that registered this
  45 + * subscription
  46 + * @param {EventSubscriptionVendor} subscriber - The subscriber that controls
  47 + * this subscription
  48 + * @param {function} listener - Function to invoke when the specified event is
  49 + * emitted
  50 + * @param {*} context - Optional context object to use when invoking the
  51 + * listener
  52 + */
  53 + constructor(
  54 + emitter: EventEmitter,
  55 + subscriber: EventSubscriptionVendor,
  56 + listener: Function,
  57 + context: ?Object
  58 + ) {
  59 + super(subscriber);
  60 + this.emitter = emitter;
  61 + this.listener = listener;
  62 + this.context = context;
  63 + }
  64 +
  65 + /**
  66 + * Removes this subscription from the emitter that registered it.
  67 + * Note: we're overriding the `remove()` method of EventSubscription here
  68 + * but deliberately not calling `super.remove()` as the responsibility
  69 + * for removing the subscription lies with the EventEmitter.
  70 + */
  71 + remove() {
  72 + this.emitter.removeSubscription(this);
  73 + }
  74 +}
  75 +
  76 +module.exports = EmitterSubscription;
  1 +/**
  2 + * Copyright (c) 2015, Facebook, Inc. All rights reserved.
  3 + *
  4 + * Facebook, Inc. ("Facebook") owns all right, title and interest, including
  5 + * all intellectual property and other proprietary rights, in and to the React
  6 + * Native CustomComponents software (the "Software"). Subject to your
  7 + * compliance with these terms, you are hereby granted a non-exclusive,
  8 + * worldwide, royalty-free copyright license to (1) use and copy the Software;
  9 + * and (2) reproduce and distribute the Software as part of your own software
  10 + * ("Your Software"). Facebook reserves all rights not expressly granted to
  11 + * you in this license agreement.
  12 + *
  13 + * THE SOFTWARE AND DOCUMENTATION, IF ANY, ARE PROVIDED "AS IS" AND ANY EXPRESS
  14 + * OR IMPLIED WARRANTIES (INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  15 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE) ARE DISCLAIMED.
  16 + * IN NO EVENT SHALL FACEBOOK OR ITS AFFILIATES, OFFICERS, DIRECTORS OR
  17 + * EMPLOYEES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  18 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  19 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  20 + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  21 + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  22 + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE SOFTWARE, EVEN IF
  23 + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  24 + *
  25 + * @noflow
  26 + * @typecheck
  27 + */
  28 +'use strict';
  29 +
  30 +const EmitterSubscription = require('./EmitterSubscription');
  31 +const EventSubscriptionVendor = require('./EventSubscriptionVendor');
  32 +
  33 +const emptyFunction = require('fbjs/lib/emptyFunction');
  34 +const invariant = require('fbjs/lib/invariant');
  35 +
  36 +/**
  37 + * @class EventEmitter
  38 + * @description
  39 + * An EventEmitter is responsible for managing a set of listeners and publishing
  40 + * events to them when it is told that such events happened. In addition to the
  41 + * data for the given event it also sends a event control object which allows
  42 + * the listeners/handlers to prevent the default behavior of the given event.
  43 + *
  44 + * The emitter is designed to be generic enough to support all the different
  45 + * contexts in which one might want to emit events. It is a simple multicast
  46 + * mechanism on top of which extra functionality can be composed. For example, a
  47 + * more advanced emitter may use an EventHolder and EventFactory.
  48 + */
  49 +class EventEmitter {
  50 +
  51 + _subscriber: EventSubscriptionVendor;
  52 + _currentSubscription: ?EmitterSubscription;
  53 +
  54 + /**
  55 + * @constructor
  56 + *
  57 + * @param {EventSubscriptionVendor} subscriber - Optional subscriber instance
  58 + * to use. If omitted, a new subscriber will be created for the emitter.
  59 + */
  60 + constructor(subscriber: ?EventSubscriptionVendor) {
  61 + this._subscriber = subscriber || new EventSubscriptionVendor();
  62 + }
  63 +
  64 + /**
  65 + * Adds a listener to be invoked when events of the specified type are
  66 + * emitted. An optional calling context may be provided. The data arguments
  67 + * emitted will be passed to the listener function.
  68 + *
  69 + * TODO: Annotate the listener arg's type. This is tricky because listeners
  70 + * can be invoked with varargs.
  71 + *
  72 + * @param {string} eventType - Name of the event to listen to
  73 + * @param {function} listener - Function to invoke when the specified event is
  74 + * emitted
  75 + * @param {*} context - Optional context object to use when invoking the
  76 + * listener
  77 + */
  78 + addListener(
  79 + eventType: string, listener: Function, context: ?Object): EmitterSubscription {
  80 +
  81 + return (this._subscriber.addSubscription(
  82 + eventType,
  83 + new EmitterSubscription(this, this._subscriber, listener, context)
  84 + ) : any);
  85 + }
  86 +
  87 + /**
  88 + * Similar to addListener, except that the listener is removed after it is
  89 + * invoked once.
  90 + *
  91 + * @param {string} eventType - Name of the event to listen to
  92 + * @param {function} listener - Function to invoke only once when the
  93 + * specified event is emitted
  94 + * @param {*} context - Optional context object to use when invoking the
  95 + * listener
  96 + */
  97 + once(eventType: string, listener: Function, context: ?Object): EmitterSubscription {
  98 + return this.addListener(eventType, (...args) => {
  99 + this.removeCurrentListener();
  100 + listener.apply(context, args);
  101 + });
  102 + }
  103 +
  104 + /**
  105 + * Removes all of the registered listeners, including those registered as
  106 + * listener maps.
  107 + *
  108 + * @param {?string} eventType - Optional name of the event whose registered
  109 + * listeners to remove
  110 + */
  111 + removeAllListeners(eventType: ?string) {
  112 + this._subscriber.removeAllSubscriptions(eventType);
  113 + }
  114 +
  115 + /**
  116 + * Provides an API that can be called during an eventing cycle to remove the
  117 + * last listener that was invoked. This allows a developer to provide an event
  118 + * object that can remove the listener (or listener map) during the
  119 + * invocation.
  120 + *
  121 + * If it is called when not inside of an emitting cycle it will throw.
  122 + *
  123 + * @throws {Error} When called not during an eventing cycle
  124 + *
  125 + * @example
  126 + * var subscription = emitter.addListenerMap({
  127 + * someEvent: function(data, event) {
  128 + * console.log(data);
  129 + * emitter.removeCurrentListener();
  130 + * }
  131 + * });
  132 + *
  133 + * emitter.emit('someEvent', 'abc'); // logs 'abc'
  134 + * emitter.emit('someEvent', 'def'); // does not log anything
  135 + */
  136 + removeCurrentListener() {
  137 + invariant(
  138 + !!this._currentSubscription,
  139 + 'Not in an emitting cycle; there is no current subscription'
  140 + );
  141 + this.removeSubscription(this._currentSubscription);
  142 + }
  143 +
  144 + /**
  145 + * Removes a specific subscription. Called by the `remove()` method of the
  146 + * subscription itself to ensure any necessary cleanup is performed.
  147 + */
  148 + removeSubscription(subscription: EmitterSubscription) {
  149 + invariant(
  150 + subscription.emitter === this,
  151 + 'Subscription does not belong to this emitter.'
  152 + );
  153 + this._subscriber.removeSubscription(subscription);
  154 + }
  155 +
  156 + /**
  157 + * Returns an array of listeners that are currently registered for the given
  158 + * event.
  159 + *
  160 + * @param {string} eventType - Name of the event to query
  161 + * @returns {array}
  162 + */
  163 + listeners(eventType: string): [EmitterSubscription] {
  164 + const subscriptions: ?[EmitterSubscription] = (this._subscriber.getSubscriptionsForType(eventType): any);
  165 + return subscriptions
  166 + ? subscriptions.filter(emptyFunction.thatReturnsTrue).map(
  167 + function(subscription) {
  168 + return subscription.listener;
  169 + })
  170 + : [];
  171 + }
  172 +
  173 + /**
  174 + * Emits an event of the given type with the given data. All handlers of that
  175 + * particular type will be notified.
  176 + *
  177 + * @param {string} eventType - Name of the event to emit
  178 + * @param {...*} Arbitrary arguments to be passed to each registered listener
  179 + *
  180 + * @example
  181 + * emitter.addListener('someEvent', function(message) {
  182 + * console.log(message);
  183 + * });
  184 + *
  185 + * emitter.emit('someEvent', 'abc'); // logs 'abc'
  186 + */
  187 + emit(eventType: string) {
  188 + const subscriptions: ?[EmitterSubscription] = (this._subscriber.getSubscriptionsForType(eventType): any);
  189 + if (subscriptions) {
  190 + for (let i = 0, l = subscriptions.length; i < l; i++) {
  191 + const subscription = subscriptions[i];
  192 +
  193 + // The subscription may have been removed during this event loop.
  194 + if (subscription) {
  195 + this._currentSubscription = subscription;
  196 + subscription.listener.apply(
  197 + subscription.context,
  198 + Array.prototype.slice.call(arguments, 1)
  199 + );
  200 + }
  201 + }
  202 + this._currentSubscription = null;
  203 + }
  204 + }
  205 +
  206 + /**
  207 + * Removes the given listener for event of specific type.
  208 + *
  209 + * @param {string} eventType - Name of the event to emit
  210 + * @param {function} listener - Function to invoke when the specified event is
  211 + * emitted
  212 + *
  213 + * @example
  214 + * emitter.removeListener('someEvent', function(message) {
  215 + * console.log(message);
  216 + * }); // removes the listener if already registered
  217 + *
  218 + */
  219 + removeListener(eventType: String, listener) {
  220 + const subscriptions: ?[EmitterSubscription] = (this._subscriber.getSubscriptionsForType(eventType): any);
  221 + if (subscriptions) {
  222 + for (let i = 0, l = subscriptions.length; i < l; i++) {
  223 + const subscription = subscriptions[i];
  224 +
  225 + // The subscription may have been removed during this event loop.
  226 + // its listener matches the listener in method parameters
  227 + if (subscription && subscription.listener === listener) {
  228 + subscription.remove();
  229 + }
  230 + }
  231 + }
  232 + }
  233 +}
  234 +
  235 +module.exports = EventEmitter;
  1 +/**
  2 + * Copyright (c) 2015, Facebook, Inc. All rights reserved.
  3 + *
  4 + * Facebook, Inc. ("Facebook") owns all right, title and interest, including
  5 + * all intellectual property and other proprietary rights, in and to the React
  6 + * Native CustomComponents software (the "Software"). Subject to your
  7 + * compliance with these terms, you are hereby granted a non-exclusive,
  8 + * worldwide, royalty-free copyright license to (1) use and copy the Software;
  9 + * and (2) reproduce and distribute the Software as part of your own software
  10 + * ("Your Software"). Facebook reserves all rights not expressly granted to
  11 + * you in this license agreement.
  12 + *
  13 + * THE SOFTWARE AND DOCUMENTATION, IF ANY, ARE PROVIDED "AS IS" AND ANY EXPRESS
  14 + * OR IMPLIED WARRANTIES (INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  15 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE) ARE DISCLAIMED.
  16 + * IN NO EVENT SHALL FACEBOOK OR ITS AFFILIATES, OFFICERS, DIRECTORS OR
  17 + * EMPLOYEES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  18 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  19 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  20 + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  21 + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  22 + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE SOFTWARE, EVEN IF
  23 + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  24 + *
  25 + * @flow
  26 + */
  27 +'use strict';
  28 +
  29 +import type EventSubscriptionVendor from './EventSubscriptionVendor';
  30 +
  31 +/**
  32 + * EventSubscription represents a subscription to a particular event. It can
  33 + * remove its own subscription.
  34 + */
  35 +class EventSubscription {
  36 +
  37 + eventType: string;
  38 + key: number;
  39 + subscriber: EventSubscriptionVendor;
  40 +
  41 + /**
  42 + * @param {EventSubscriptionVendor} subscriber the subscriber that controls
  43 + * this subscription.
  44 + */
  45 + constructor(subscriber: EventSubscriptionVendor) {
  46 + this.subscriber = subscriber;
  47 + }
  48 +
  49 + /**
  50 + * Removes this subscription from the subscriber that controls it.
  51 + */
  52 + remove() {
  53 + this.subscriber.removeSubscription(this);
  54 + }
  55 +}
  56 +
  57 +module.exports = EventSubscription;
  1 +/**
  2 + * Copyright (c) 2015, Facebook, Inc. All rights reserved.
  3 + *
  4 + * Facebook, Inc. ("Facebook") owns all right, title and interest, including
  5 + * all intellectual property and other proprietary rights, in and to the React
  6 + * Native CustomComponents software (the "Software"). Subject to your
  7 + * compliance with these terms, you are hereby granted a non-exclusive,
  8 + * worldwide, royalty-free copyright license to (1) use and copy the Software;
  9 + * and (2) reproduce and distribute the Software as part of your own software
  10 + * ("Your Software"). Facebook reserves all rights not expressly granted to
  11 + * you in this license agreement.
  12 + *
  13 + * THE SOFTWARE AND DOCUMENTATION, IF ANY, ARE PROVIDED "AS IS" AND ANY EXPRESS
  14 + * OR IMPLIED WARRANTIES (INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  15 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE) ARE DISCLAIMED.
  16 + * IN NO EVENT SHALL FACEBOOK OR ITS AFFILIATES, OFFICERS, DIRECTORS OR
  17 + * EMPLOYEES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  18 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  19 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  20 + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  21 + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  22 + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE SOFTWARE, EVEN IF
  23 + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  24 + *
  25 + * @flow
  26 + */
  27 +'use strict';
  28 +
  29 +const invariant = require('fbjs/lib/invariant');
  30 +
  31 +import type EventSubscription from './EventSubscription';
  32 +
  33 +/**
  34 + * EventSubscriptionVendor stores a set of EventSubscriptions that are
  35 + * subscribed to a particular event type.
  36 + */
  37 +class EventSubscriptionVendor {
  38 +
  39 + _subscriptionsForType: Object;
  40 + _currentSubscription: ?EventSubscription;
  41 +
  42 + constructor() {
  43 + this._subscriptionsForType = {};
  44 + this._currentSubscription = null;
  45 + }
  46 +
  47 + /**
  48 + * Adds a subscription keyed by an event type.
  49 + *
  50 + * @param {string} eventType
  51 + * @param {EventSubscription} subscription
  52 + */
  53 + addSubscription(
  54 + eventType: string, subscription: EventSubscription): EventSubscription {
  55 + invariant(
  56 + subscription.subscriber === this,
  57 + 'The subscriber of the subscription is incorrectly set.');
  58 + if (!this._subscriptionsForType[eventType]) {
  59 + this._subscriptionsForType[eventType] = [];
  60 + }
  61 + const key = this._subscriptionsForType[eventType].length;
  62 + this._subscriptionsForType[eventType].push(subscription);
  63 + subscription.eventType = eventType;
  64 + subscription.key = key;
  65 + return subscription;
  66 + }
  67 +
  68 + /**
  69 + * Removes a bulk set of the subscriptions.
  70 + *
  71 + * @param {?string} eventType - Optional name of the event type whose
  72 + * registered supscriptions to remove, if null remove all subscriptions.
  73 + */
  74 + removeAllSubscriptions(eventType: ?string) {
  75 + if (eventType === undefined) {
  76 + this._subscriptionsForType = {};
  77 + } else {
  78 + delete this._subscriptionsForType[eventType];
  79 + }
  80 + }
  81 +
  82 + /**
  83 + * Removes a specific subscription. Instead of calling this function, call
  84 + * `subscription.remove()` directly.
  85 + *
  86 + * @param {object} subscription
  87 + */
  88 + removeSubscription(subscription: Object) {
  89 + const eventType = subscription.eventType;
  90 + const key = subscription.key;
  91 +
  92 + const subscriptionsForType = this._subscriptionsForType[eventType];
  93 + if (subscriptionsForType) {
  94 + delete subscriptionsForType[key];
  95 + }
  96 + }
  97 +
  98 + /**
  99 + * Returns the array of subscriptions that are currently registered for the
  100 + * given event type.
  101 + *
  102 + * Note: This array can be potentially sparse as subscriptions are deleted
  103 + * from it when they are removed.
  104 + *
  105 + * TODO: This returns a nullable array. wat?
  106 + *
  107 + * @param {string} eventType
  108 + * @returns {?array}
  109 + */
  110 + getSubscriptionsForType(eventType: string): ?[EventSubscription] {
  111 + return this._subscriptionsForType[eventType];
  112 + }
  113 +}
  114 +
  115 +module.exports = EventSubscriptionVendor;
  1 +/**
  2 + * Copyright (c) 2015, Facebook, Inc. All rights reserved.
  3 + *
  4 + * Facebook, Inc. ("Facebook") owns all right, title and interest, including
  5 + * all intellectual property and other proprietary rights, in and to the React
  6 + * Native CustomComponents software (the "Software"). Subject to your
  7 + * compliance with these terms, you are hereby granted a non-exclusive,
  8 + * worldwide, royalty-free copyright license to (1) use and copy the Software;
  9 + * and (2) reproduce and distribute the Software as part of your own software
  10 + * ("Your Software"). Facebook reserves all rights not expressly granted to
  11 + * you in this license agreement.
  12 + *
  13 + * THE SOFTWARE AND DOCUMENTATION, IF ANY, ARE PROVIDED "AS IS" AND ANY EXPRESS
  14 + * OR IMPLIED WARRANTIES (INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  15 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE) ARE DISCLAIMED.
  16 + * IN NO EVENT SHALL FACEBOOK OR ITS AFFILIATES, OFFICERS, DIRECTORS OR
  17 + * EMPLOYEES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  18 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  19 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  20 + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  21 + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  22 + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE SOFTWARE, EVEN IF
  23 + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  24 + *
  25 + * @flow
  26 + */
  27 +'use strict';
  28 +
  29 +import {InteractionManager} from 'react-native';
  30 +
  31 +/**
  32 + * This mixin provides safe versions of InteractionManager start/end methods
  33 + * that ensures `clearInteractionHandle` is always called
  34 + * once per start, even if the component is unmounted.
  35 + */
  36 +var InteractionMixin = {
  37 + componentWillUnmount: function() {
  38 + while (this._interactionMixinHandles.length) {
  39 + InteractionManager.clearInteractionHandle(
  40 + this._interactionMixinHandles.pop()
  41 + );
  42 + }
  43 + },
  44 +
  45 + _interactionMixinHandles: ([]: Array<number>),
  46 +
  47 + createInteractionHandle: function() {
  48 + var handle = InteractionManager.createInteractionHandle();
  49 + this._interactionMixinHandles.push(handle);
  50 + return handle;
  51 + },
  52 +
  53 + clearInteractionHandle: function(clearHandle: number) {
  54 + InteractionManager.clearInteractionHandle(clearHandle);
  55 + this._interactionMixinHandles = this._interactionMixinHandles.filter(
  56 + handle => handle !== clearHandle
  57 + );
  58 + },
  59 +
  60 + /**
  61 + * Schedule work for after all interactions have completed.
  62 + *
  63 + * @param {function} callback
  64 + */
  65 + runAfterInteractions: function(callback: Function) {
  66 + InteractionManager.runAfterInteractions(callback);
  67 + },
  68 +};
  69 +
  70 +module.exports = InteractionMixin;
  1 +/**
  2 + * Copyright (c) 2015, Facebook, Inc. All rights reserved.
  3 + *
  4 + * Facebook, Inc. ("Facebook") owns all right, title and interest, including
  5 + * all intellectual property and other proprietary rights, in and to the React
  6 + * Native CustomComponents software (the "Software"). Subject to your
  7 + * compliance with these terms, you are hereby granted a non-exclusive,
  8 + * worldwide, royalty-free copyright license to (1) use and copy the Software;
  9 + * and (2) reproduce and distribute the Software as part of your own software
  10 + * ("Your Software"). Facebook reserves all rights not expressly granted to
  11 + * you in this license agreement.
  12 + *
  13 + * THE SOFTWARE AND DOCUMENTATION, IF ANY, ARE PROVIDED "AS IS" AND ANY EXPRESS
  14 + * OR IMPLIED WARRANTIES (INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  15 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE) ARE DISCLAIMED.
  16 + * IN NO EVENT SHALL FACEBOOK OR ITS AFFILIATES, OFFICERS, DIRECTORS OR
  17 + * EMPLOYEES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  18 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  19 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  20 + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  21 + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  22 + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE SOFTWARE, EVEN IF
  23 + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  24 + *
  25 + * @noflow
  26 + */
  27 +'use strict';
  28 +
  29 +var NavigationEvent = require('./NavigationEvent');
  30 +var NavigationEventEmitter = require('./NavigationEventEmitter');
  31 +var NavigationTreeNode = require('./NavigationTreeNode');
  32 +
  33 +var emptyFunction = require('fbjs/lib/emptyFunction');
  34 +var invariant = require('fbjs/lib/invariant');
  35 +
  36 +import type EventSubscription from 'EventSubscription';
  37 +
  38 +var {
  39 + AT_TARGET,
  40 + BUBBLING_PHASE,
  41 + CAPTURING_PHASE,
  42 +} = NavigationEvent;
  43 +
  44 +// Event types that do not support event bubbling, capturing and
  45 +// reconciliation API (e.g event.preventDefault(), event.stopPropagation()).
  46 +var LegacyEventTypes = new Set([
  47 + 'willfocus',
  48 + 'didfocus',
  49 +]);
  50 +
  51 +/**
  52 + * Class that contains the info and methods for app navigation.
  53 + */
  54 +class NavigationContext {
  55 + __node: NavigationTreeNode;
  56 + _bubbleEventEmitter: ?NavigationEventEmitter;
  57 + _captureEventEmitter: ?NavigationEventEmitter;
  58 + _currentRoute: any;
  59 + _emitCounter: number;
  60 + _emitQueue: Array<any>;
  61 +
  62 + constructor() {
  63 + this._bubbleEventEmitter = new NavigationEventEmitter(this);
  64 + this._captureEventEmitter = new NavigationEventEmitter(this);
  65 + this._currentRoute = null;
  66 +
  67 + // Sets the protected property `__node`.
  68 + this.__node = new NavigationTreeNode(this);
  69 +
  70 + this._emitCounter = 0;
  71 + this._emitQueue = [];
  72 +
  73 + this.addListener('willfocus', this._onFocus);
  74 + this.addListener('didfocus', this._onFocus);
  75 + }
  76 +
  77 + /* $FlowFixMe - get/set properties not yet supported */
  78 + get parent(): ?NavigationContext {
  79 + var parent = this.__node.getParent();
  80 + return parent ? parent.getValue() : null;
  81 + }
  82 +
  83 + /* $FlowFixMe - get/set properties not yet supported */
  84 + get top(): ?NavigationContext {
  85 + var result = null;
  86 + var parentNode = this.__node.getParent();
  87 + while (parentNode) {
  88 + result = parentNode.getValue();
  89 + parentNode = parentNode.getParent();
  90 + }
  91 + return result;
  92 + }
  93 +
  94 + /* $FlowFixMe - get/set properties not yet supported */
  95 + get currentRoute(): any {
  96 + return this._currentRoute;
  97 + }
  98 +
  99 + appendChild(childContext: NavigationContext): void {
  100 + this.__node.appendChild(childContext.__node);
  101 + }
  102 +
  103 + addListener(
  104 + eventType: string,
  105 + listener: Function,
  106 + useCapture: ?boolean
  107 + ): EventSubscription {
  108 + if (LegacyEventTypes.has(eventType)) {
  109 + useCapture = false;
  110 + }
  111 +
  112 + var emitter = useCapture ?
  113 + this._captureEventEmitter :
  114 + this._bubbleEventEmitter;
  115 +
  116 + if (emitter) {
  117 + return emitter.addListener(eventType, listener, this);
  118 + } else {
  119 + return {remove: emptyFunction};
  120 + }
  121 + }
  122 +
  123 + emit(eventType: String, data: any, didEmitCallback: ?Function): void {
  124 + if (this._emitCounter > 0) {
  125 + // An event cycle that was previously created hasn't finished yet.
  126 + // Put this event cycle into the queue and will finish them later.
  127 + var args: any = Array.prototype.slice.call(arguments);
  128 + this._emitQueue.push(args);
  129 + return;
  130 + }
  131 +
  132 + this._emitCounter++;
  133 +
  134 + if (LegacyEventTypes.has(eventType)) {
  135 + // Legacy events does not support event bubbling and reconciliation.
  136 + this.__emit(
  137 + eventType,
  138 + data,
  139 + null,
  140 + {
  141 + defaultPrevented: false,
  142 + eventPhase: AT_TARGET,
  143 + propagationStopped: true,
  144 + target: this,
  145 + }
  146 + );
  147 + } else {
  148 + var targets = [this];
  149 + var parentTarget = this.parent;
  150 + while (parentTarget) {
  151 + targets.unshift(parentTarget);
  152 + parentTarget = parentTarget.parent;
  153 + }
  154 +
  155 + var propagationStopped = false;
  156 + var defaultPrevented = false;
  157 + var callback = (event) => {
  158 + propagationStopped = propagationStopped || event.isPropagationStopped();
  159 + defaultPrevented = defaultPrevented || event.defaultPrevented;
  160 + };
  161 +
  162 + // Capture phase
  163 + targets.some((currentTarget) => {
  164 + if (propagationStopped) {
  165 + return true;
  166 + }
  167 +
  168 + var extraInfo = {
  169 + defaultPrevented,
  170 + eventPhase: CAPTURING_PHASE,
  171 + propagationStopped,
  172 + target: this,
  173 + };
  174 +
  175 + currentTarget.__emit(eventType, data, callback, extraInfo);
  176 + }, this);
  177 +
  178 + // bubble phase
  179 + targets.reverse().some((currentTarget) => {
  180 + if (propagationStopped) {
  181 + return true;
  182 + }
  183 + var extraInfo = {
  184 + defaultPrevented,
  185 + eventPhase: BUBBLING_PHASE,
  186 + propagationStopped,
  187 + target: this,
  188 + };
  189 + currentTarget.__emit(eventType, data, callback, extraInfo);
  190 + }, this);
  191 + }
  192 +
  193 + if (didEmitCallback) {
  194 + var event = NavigationEvent.pool(eventType, this, data);
  195 + propagationStopped && event.stopPropagation();
  196 + defaultPrevented && event.preventDefault();
  197 + didEmitCallback.call(this, event);
  198 + event.dispose();
  199 + }
  200 +
  201 + this._emitCounter--;
  202 + while (this._emitQueue.length) {
  203 + var args: any = this._emitQueue.shift();
  204 + this.emit.apply(this, args);
  205 + }
  206 + }
  207 +
  208 + dispose(): void {
  209 + // clean up everything.
  210 + this._bubbleEventEmitter && this._bubbleEventEmitter.removeAllListeners();
  211 + this._captureEventEmitter && this._captureEventEmitter.removeAllListeners();
  212 + this._bubbleEventEmitter = null;
  213 + this._captureEventEmitter = null;
  214 + this._currentRoute = null;
  215 + }
  216 +
  217 + // This method `__method` is protected.
  218 + __emit(
  219 + eventType: String,
  220 + data: any,
  221 + didEmitCallback: ?Function,
  222 + extraInfo: Object,
  223 + ): void {
  224 + var emitter;
  225 + switch (extraInfo.eventPhase) {
  226 + case CAPTURING_PHASE: // phase = 1
  227 + emitter = this._captureEventEmitter;
  228 + break;
  229 +
  230 + case AT_TARGET: // phase = 2
  231 + emitter = this._bubbleEventEmitter;
  232 + break;
  233 +
  234 + case BUBBLING_PHASE: // phase = 3
  235 + emitter = this._bubbleEventEmitter;
  236 + break;
  237 +
  238 + default:
  239 + invariant(false, 'invalid event phase %s', extraInfo.eventPhase);
  240 + }
  241 +
  242 + if (extraInfo.target === this) {
  243 + // phase = 2
  244 + extraInfo.eventPhase = AT_TARGET;
  245 + }
  246 +
  247 + if (emitter) {
  248 + emitter.emit(
  249 + eventType,
  250 + data,
  251 + didEmitCallback,
  252 + extraInfo
  253 + );
  254 + }
  255 + }
  256 +
  257 + _onFocus(event: NavigationEvent): void {
  258 + invariant(
  259 + event.data && event.data.hasOwnProperty('route'),
  260 + 'event type "%s" should provide route',
  261 + event.type
  262 + );
  263 +
  264 + this._currentRoute = event.data.route;
  265 + }
  266 +}
  267 +
  268 +module.exports = NavigationContext;
  1 +/**
  2 + * Copyright (c) 2015, Facebook, Inc. All rights reserved.
  3 + *
  4 + * Facebook, Inc. ("Facebook") owns all right, title and interest, including
  5 + * all intellectual property and other proprietary rights, in and to the React
  6 + * Native CustomComponents software (the "Software"). Subject to your
  7 + * compliance with these terms, you are hereby granted a non-exclusive,
  8 + * worldwide, royalty-free copyright license to (1) use and copy the Software;
  9 + * and (2) reproduce and distribute the Software as part of your own software
  10 + * ("Your Software"). Facebook reserves all rights not expressly granted to
  11 + * you in this license agreement.
  12 + *
  13 + * THE SOFTWARE AND DOCUMENTATION, IF ANY, ARE PROVIDED "AS IS" AND ANY EXPRESS
  14 + * OR IMPLIED WARRANTIES (INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  15 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE) ARE DISCLAIMED.
  16 + * IN NO EVENT SHALL FACEBOOK OR ITS AFFILIATES, OFFICERS, DIRECTORS OR
  17 + * EMPLOYEES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  18 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  19 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  20 + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  21 + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  22 + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE SOFTWARE, EVEN IF
  23 + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  24 + *
  25 + * @flow
  26 + */
  27 +'use strict';
  28 +
  29 +const invariant = require('fbjs/lib/invariant');
  30 +
  31 +class NavigationEventPool {
  32 + _list: Array<any>;
  33 +
  34 + constructor() {
  35 + this._list = [];
  36 + }
  37 +
  38 + get(type: string, currentTarget: Object, data: any): NavigationEvent {
  39 + let event;
  40 + if (this._list.length > 0) {
  41 + event = this._list.pop();
  42 + event.constructor.call(event, type, currentTarget, data);
  43 + } else {
  44 + event = new NavigationEvent(type, currentTarget, data);
  45 + }
  46 + return event;
  47 + }
  48 +
  49 + put(event: NavigationEvent) {
  50 + this._list.push(event);
  51 + }
  52 +}
  53 +
  54 +const _navigationEventPool = new NavigationEventPool();
  55 +
  56 +/**
  57 + * The NavigationEvent interface represents any event of the navigation.
  58 + * It contains common properties and methods to any event.
  59 + *
  60 + * == Important Properties ==
  61 + *
  62 + * - target:
  63 + * A reference to the navigation context that dispatched the event. It is
  64 + * different from event.currentTarget when the event handler is called during
  65 + * the bubbling or capturing phase of the event.
  66 + *
  67 + * - currentTarget:
  68 + * Identifies the current target for the event, as the event traverses the
  69 + * navigation context tree. It always refers to the navigation context the
  70 + * event handler has been attached to as opposed to event.target which
  71 + * identifies the navigation context on which the event occurred.
  72 + *
  73 + * - eventPhase:
  74 + * Returns an integer value which specifies the current evaluation phase of
  75 + * the event flow; possible values are listed in NavigationEvent phase
  76 + * constants below.
  77 + */
  78 +class NavigationEvent {
  79 + static AT_TARGET: number;
  80 + static BUBBLING_PHASE: number;
  81 + static CAPTURING_PHASE: number;
  82 + static NONE: number;
  83 +
  84 + _currentTarget: ?Object;
  85 + _data: any;
  86 + _defaultPrevented: boolean;
  87 + _disposed: boolean;
  88 + _propagationStopped: boolean;
  89 + _type: string;
  90 +
  91 + target: ?Object;
  92 +
  93 + // Returns an integer value which specifies the current evaluation phase of
  94 + // the event flow.
  95 + eventPhase: number;
  96 +
  97 + static pool(type: string, currentTarget: Object, data: any): NavigationEvent {
  98 + return _navigationEventPool.get(type, currentTarget, data);
  99 + }
  100 +
  101 + constructor(type: string, currentTarget: Object, data: any) {
  102 + this.target = currentTarget;
  103 + this.eventPhase = NavigationEvent.NONE;
  104 +
  105 + this._type = type;
  106 + this._currentTarget = currentTarget;
  107 + this._data = data;
  108 + this._defaultPrevented = false;
  109 + this._disposed = false;
  110 + this._propagationStopped = false;
  111 + }
  112 +
  113 + get type(): string {
  114 + return this._type;
  115 + }
  116 +
  117 + get currentTarget(): ?Object {
  118 + return this._currentTarget;
  119 + }
  120 +
  121 + get data(): any {
  122 + return this._data;
  123 + }
  124 +
  125 + get defaultPrevented(): boolean {
  126 + return this._defaultPrevented;
  127 + }
  128 +
  129 + preventDefault(): void {
  130 + this._defaultPrevented = true;
  131 + }
  132 +
  133 + stopPropagation(): void {
  134 + this._propagationStopped = true;
  135 + }
  136 +
  137 + stop(): void {
  138 + this.preventDefault();
  139 + this.stopPropagation();
  140 + }
  141 +
  142 + isPropagationStopped(): boolean {
  143 + return this._propagationStopped;
  144 + }
  145 +
  146 + /**
  147 + * Dispose the event.
  148 + * NavigationEvent shall be disposed after being emitted by
  149 + * `NavigationEventEmitter`.
  150 + */
  151 + dispose(): void {
  152 + invariant(!this._disposed, 'NavigationEvent is already disposed');
  153 + this._disposed = true;
  154 +
  155 + // Clean up.
  156 + this.target = null;
  157 + this.eventPhase = NavigationEvent.NONE;
  158 + this._type = '';
  159 + this._currentTarget = null;
  160 + this._data = null;
  161 + this._defaultPrevented = false;
  162 +
  163 + // Put this back to the pool to reuse the instance.
  164 + _navigationEventPool.put(this);
  165 + }
  166 +}
  167 +
  168 +/**
  169 + * Event phase constants.
  170 + * These values describe which phase the event flow is currently being
  171 + * evaluated.
  172 + */
  173 +
  174 +// No event is being processed at this time.
  175 +NavigationEvent.NONE = 0;
  176 +
  177 +// The event is being propagated through the currentTarget's ancestor objects.
  178 +NavigationEvent.CAPTURING_PHASE = 1;
  179 +
  180 +// The event has arrived at the event's currentTarget. Event listeners registered for
  181 +// this phase are called at this time.
  182 +NavigationEvent.AT_TARGET = 2;
  183 +
  184 +// The event is propagating back up through the currentTarget's ancestors in reverse
  185 +// order, starting with the parent. This is known as bubbling, and occurs only
  186 +// if event propagation isn't prevented. Event listeners registered for this
  187 +// phase are triggered during this process.
  188 +NavigationEvent.BUBBLING_PHASE = 3;
  189 +
  190 +module.exports = NavigationEvent;
  1 +/**
  2 + * Copyright (c) 2015, Facebook, Inc. All rights reserved.
  3 + *
  4 + * Facebook, Inc. ("Facebook") owns all right, title and interest, including
  5 + * all intellectual property and other proprietary rights, in and to the React
  6 + * Native CustomComponents software (the "Software"). Subject to your
  7 + * compliance with these terms, you are hereby granted a non-exclusive,
  8 + * worldwide, royalty-free copyright license to (1) use and copy the Software;
  9 + * and (2) reproduce and distribute the Software as part of your own software
  10 + * ("Your Software"). Facebook reserves all rights not expressly granted to
  11 + * you in this license agreement.
  12 + *
  13 + * THE SOFTWARE AND DOCUMENTATION, IF ANY, ARE PROVIDED "AS IS" AND ANY EXPRESS
  14 + * OR IMPLIED WARRANTIES (INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  15 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE) ARE DISCLAIMED.
  16 + * IN NO EVENT SHALL FACEBOOK OR ITS AFFILIATES, OFFICERS, DIRECTORS OR
  17 + * EMPLOYEES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  18 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  19 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  20 + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  21 + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  22 + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE SOFTWARE, EVEN IF
  23 + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  24 + *
  25 + * @flow
  26 + */
  27 +'use strict';
  28 +
  29 +var EventEmitter = require('./EventEmitter');
  30 +var NavigationEvent = require('./NavigationEvent');
  31 +
  32 +type ExtraInfo = {
  33 + defaultPrevented: ?boolean,
  34 + eventPhase: ?number,
  35 + propagationStopped: ?boolean,
  36 + target: ?Object,
  37 +};
  38 +
  39 +class NavigationEventEmitter extends EventEmitter {
  40 + _emitQueue: Array<any>;
  41 + _emitting: boolean;
  42 + _target: Object;
  43 +
  44 + constructor(target: Object) {
  45 + super();
  46 + this._emitting = false;
  47 + this._emitQueue = [];
  48 + this._target = target;
  49 + }
  50 +
  51 + emit(
  52 + eventType: string,
  53 + data: any,
  54 + didEmitCallback: ?Function,
  55 + extraInfo: ?ExtraInfo
  56 + ): void {
  57 + if (this._emitting) {
  58 + // An event cycle that was previously created hasn't finished yet.
  59 + // Put this event cycle into the queue and will finish them later.
  60 + var args: any = Array.prototype.slice.call(arguments);
  61 + this._emitQueue.push(args);
  62 + return;
  63 + }
  64 +
  65 + this._emitting = true;
  66 +
  67 + var event = NavigationEvent.pool(eventType, this._target, data);
  68 +
  69 + if (extraInfo) {
  70 + if (extraInfo.target) {
  71 + event.target = extraInfo.target;
  72 + }
  73 +
  74 + if (extraInfo.eventPhase) {
  75 + event.eventPhase = extraInfo.eventPhase;
  76 + }
  77 +
  78 + if (extraInfo.defaultPrevented) {
  79 + event.preventDefault();
  80 + }
  81 +
  82 + if (extraInfo.propagationStopped) {
  83 + event.stopPropagation();
  84 + }
  85 + }
  86 +
  87 + // EventEmitter#emit only takes `eventType` as `String`. Casting `eventType`
  88 + // to `String` to make @flow happy.
  89 + super.emit(String(eventType), event);
  90 +
  91 + if (typeof didEmitCallback === 'function') {
  92 + didEmitCallback.call(this._target, event);
  93 + }
  94 + event.dispose();
  95 +
  96 + this._emitting = false;
  97 +
  98 + while (this._emitQueue.length) {
  99 + var args: any = this._emitQueue.shift();
  100 + this.emit.apply(this, args);
  101 + }
  102 + }
  103 +}
  104 +
  105 +module.exports = NavigationEventEmitter;
  1 +/**
  2 + * Copyright (c) 2015, Facebook, Inc. All rights reserved.
  3 + *
  4 + * Facebook, Inc. ("Facebook") owns all right, title and interest, including
  5 + * all intellectual property and other proprietary rights, in and to the React
  6 + * Native CustomComponents software (the "Software"). Subject to your
  7 + * compliance with these terms, you are hereby granted a non-exclusive,
  8 + * worldwide, royalty-free copyright license to (1) use and copy the Software;
  9 + * and (2) reproduce and distribute the Software as part of your own software
  10 + * ("Your Software"). Facebook reserves all rights not expressly granted to
  11 + * you in this license agreement.
  12 + *
  13 + * THE SOFTWARE AND DOCUMENTATION, IF ANY, ARE PROVIDED "AS IS" AND ANY EXPRESS
  14 + * OR IMPLIED WARRANTIES (INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  15 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE) ARE DISCLAIMED.
  16 + * IN NO EVENT SHALL FACEBOOK OR ITS AFFILIATES, OFFICERS, DIRECTORS OR
  17 + * EMPLOYEES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  18 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  19 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  20 + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  21 + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  22 + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE SOFTWARE, EVEN IF
  23 + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  24 + *
  25 + * @flow
  26 + */
  27 +'use strict';
  28 +
  29 +var immutable = require('immutable');
  30 +var invariant = require('fbjs/lib/invariant');
  31 +
  32 +type IterationCallback = (route: any, index: number, key: string) => void;
  33 +
  34 +var {List, Set} = immutable;
  35 +
  36 +function isRouteEmpty(route: any): boolean {
  37 + return (route === undefined || route === null || route === '') || false;
  38 +}
  39 +
  40 +var _nextID = 0;
  41 +
  42 +class RouteNode {
  43 + key: string;
  44 + value: any;
  45 + constructor(route: any) {
  46 + // Key value gets bigger incrementally. Developer can compare the
  47 + // keys of two routes then know which route is added to the stack
  48 + // earlier.
  49 + this.key = String(_nextID++);
  50 +
  51 + this.value = route;
  52 + }
  53 +}
  54 +
  55 +var StackDiffRecord = immutable.Record({
  56 + key: null,
  57 + route: null,
  58 + index: null,
  59 +});
  60 +
  61 +/**
  62 + * The immutable route stack.
  63 + */
  64 +class RouteStack {
  65 + _index: number;
  66 +
  67 + _routeNodes: List<RouteNode>;
  68 +
  69 + constructor(index: number, routeNodes: List<RouteNode>) {
  70 + invariant(
  71 + routeNodes.size > 0,
  72 + 'size must not be empty'
  73 + );
  74 +
  75 + invariant(
  76 + index > -1 && index <= routeNodes.size - 1,
  77 + 'index out of bound'
  78 + );
  79 +
  80 + this._routeNodes = routeNodes;
  81 + this._index = index;
  82 + }
  83 +
  84 + get size(): number {
  85 + return this._routeNodes.size;
  86 + }
  87 +
  88 + get index(): number {
  89 + return this._index;
  90 + }
  91 +
  92 + toArray(): Array<any> {
  93 + var result = [];
  94 + var ii = 0;
  95 + var nodes = this._routeNodes;
  96 + while (ii < nodes.size) {
  97 + result.push(nodes.get(ii).value);
  98 + ii++;
  99 + }
  100 + return result;
  101 + }
  102 +
  103 + get(index: number): any {
  104 + if (index < 0 || index > this._routeNodes.size - 1) {
  105 + return null;
  106 + }
  107 + return this._routeNodes.get(index).value;
  108 + }
  109 +
  110 + /**
  111 + * Returns the key associated with the route.
  112 + * When a route is added to a stack, the stack creates a key for this route.
  113 + * The key will persist until the initial stack and its derived stack
  114 + * no longer contains this route.
  115 + */
  116 + keyOf(route: any): ?string {
  117 + if (isRouteEmpty(route)) {
  118 + return null;
  119 + }
  120 + var index = this.indexOf(route);
  121 + return index > -1 ?
  122 + this._routeNodes.get(index).key :
  123 + null;
  124 + }
  125 +
  126 + indexOf(route: any): number {
  127 + if (isRouteEmpty(route)) {
  128 + return -1;
  129 + }
  130 +
  131 + var finder = (node) => {
  132 + return (node: RouteNode).value === route;
  133 + };
  134 +
  135 + return this._routeNodes.findIndex(finder, this);
  136 + }
  137 +
  138 + slice(begin?: number, end?: number): RouteStack {
  139 + var routeNodes = this._routeNodes.slice(begin, end);
  140 + var index = Math.min(this._index, routeNodes.size - 1);
  141 + return this._update(index, routeNodes);
  142 + }
  143 +
  144 + /**
  145 + * Returns a new stack with the provided route appended,
  146 + * starting at this stack size.
  147 + */
  148 + push(route: any): RouteStack {
  149 +
  150 + invariant(
  151 + !isRouteEmpty(route),
  152 + 'Must supply route to push'
  153 + );
  154 +
  155 + invariant(this._routeNodes.indexOf(route) === -1, 'route must be unique');
  156 +
  157 + // When pushing, removes the rest of the routes past the current index.
  158 + var routeNodes = this._routeNodes.withMutations((list: List<RouteNode>) => {
  159 + list.slice(0, this._index + 1).push(new RouteNode(route));
  160 + });
  161 +
  162 + return this._update(routeNodes.size - 1, routeNodes);
  163 + }
  164 +
  165 + /**
  166 + * Returns a new stack a size ones less than this stack,
  167 + * excluding the last index in this stack.
  168 + */
  169 + pop(): RouteStack {
  170 + invariant(this._routeNodes.size > 1, 'should not pop routeNodes stack to empty');
  171 +
  172 + // When popping, removes the rest of the routes past the current index.
  173 + var routeNodes = this._routeNodes.slice(0, this._index);
  174 + return this._update(routeNodes.size - 1, routeNodes);
  175 + }
  176 +
  177 + jumpToIndex(index: number): RouteStack {
  178 + invariant(
  179 + index > -1 && index < this._routeNodes.size,
  180 + 'index out of bound'
  181 + );
  182 +
  183 + return this._update(index, this._routeNodes);
  184 + }
  185 +
  186 + /**
  187 + * Replace a route in the navigation stack.
  188 + *
  189 + * `index` specifies the route in the stack that should be replaced.
  190 + * If it's negative, it counts from the back.
  191 + */
  192 + replaceAtIndex(index: number, route: any): RouteStack {
  193 + invariant(
  194 + !isRouteEmpty(route),
  195 + 'Must supply route to replace'
  196 + );
  197 +
  198 + if (this.get(index) === route) {
  199 + return this;
  200 + }
  201 +
  202 + invariant(this.indexOf(route) === -1, 'route must be unique');
  203 +
  204 + if (index < 0) {
  205 + index += this._routeNodes.size;
  206 + }
  207 +
  208 + invariant(
  209 + index > -1 && index < this._routeNodes.size,
  210 + 'index out of bound'
  211 + );
  212 +
  213 + var routeNodes = this._routeNodes.set(index, new RouteNode(route));
  214 + return this._update(index, routeNodes);
  215 + }
  216 +
  217 + // Iterations
  218 + forEach(callback: IterationCallback, context: ?Object): void {
  219 + var ii = 0;
  220 + var nodes = this._routeNodes;
  221 + while (ii < nodes.size) {
  222 + var node = nodes.get(ii);
  223 + callback.call(context, node.value, ii, node.key);
  224 + ii++;
  225 + }
  226 + }
  227 +
  228 + mapToArray(callback: IterationCallback, context: ?Object): Array<any> {
  229 + var result = [];
  230 + this.forEach((route, index, key) => {
  231 + result.push(callback.call(context, route, index, key));
  232 + });
  233 + return result;
  234 + }
  235 +
  236 + /**
  237 + * Returns a Set excluding any routes contained within the stack given.
  238 + */
  239 + subtract(stack: RouteStack): Set<StackDiffRecord> {
  240 + var items = [];
  241 + this._routeNodes.forEach((node: RouteNode, index: number) => {
  242 + if (!stack._routeNodes.contains(node)) {
  243 + items.push(
  244 + new StackDiffRecord({
  245 + route: node.value,
  246 + index: index,
  247 + key: node.key,
  248 + })
  249 + );
  250 + }
  251 + });
  252 + return new Set(items);
  253 + }
  254 +
  255 + _update(index: number, routeNodes: List<RouteNode>): RouteStack {
  256 + if (this._index === index && this._routeNodes === routeNodes) {
  257 + return this;
  258 + }
  259 + return new RouteStack(index, routeNodes);
  260 + }
  261 +}
  262 +
  263 +/**
  264 + * The first class data structure for NavigationContext to manage the navigation
  265 + * stack of routes.
  266 + */
  267 +class NavigationRouteStack extends RouteStack {
  268 + constructor(index: number, routeNodes: Array<any>) {
  269 + // For now, `RouteStack` internally, uses an immutable `List` to keep
  270 + // track of routeNodes. Since using `List` is really just the implementation
  271 + // detail, we don't want to accept `routeNodes` as `list` from constructor
  272 + // for developer.
  273 + var nodes = routeNodes.map((route) => {
  274 + invariant(!isRouteEmpty(route), 'route must not be mepty');
  275 + return new RouteNode(route);
  276 + });
  277 +
  278 + super(index, new List(nodes));
  279 + }
  280 +}
  281 +
  282 +module.exports = NavigationRouteStack;
  1 +/**
  2 + * Copyright (c) 2015, Facebook, Inc. All rights reserved.
  3 + *
  4 + * Facebook, Inc. ("Facebook") owns all right, title and interest, including
  5 + * all intellectual property and other proprietary rights, in and to the React
  6 + * Native CustomComponents software (the "Software"). Subject to your
  7 + * compliance with these terms, you are hereby granted a non-exclusive,
  8 + * worldwide, royalty-free copyright license to (1) use and copy the Software;
  9 + * and (2) reproduce and distribute the Software as part of your own software
  10 + * ("Your Software"). Facebook reserves all rights not expressly granted to
  11 + * you in this license agreement.
  12 + *
  13 + * THE SOFTWARE AND DOCUMENTATION, IF ANY, ARE PROVIDED "AS IS" AND ANY EXPRESS
  14 + * OR IMPLIED WARRANTIES (INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  15 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE) ARE DISCLAIMED.
  16 + * IN NO EVENT SHALL FACEBOOK OR ITS AFFILIATES, OFFICERS, DIRECTORS OR
  17 + * EMPLOYEES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  18 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  19 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  20 + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  21 + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  22 + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE SOFTWARE, EVEN IF
  23 + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  24 + *
  25 + * @flow
  26 + */
  27 +'use strict';
  28 +
  29 +var invariant = require('fbjs/lib/invariant');
  30 +var immutable = require('immutable');
  31 +
  32 +var {List} = immutable;
  33 +
  34 +/**
  35 + * Utility to build a tree of nodes.
  36 + * Note that this tree does not perform cyclic redundancy check
  37 + * while appending child node.
  38 + */
  39 +class NavigationTreeNode {
  40 + __parent: ?NavigationTreeNode;
  41 +
  42 + _children: List<NavigationTreeNode>;
  43 +
  44 + _value: any;
  45 +
  46 + constructor(value: any) {
  47 + this.__parent = null;
  48 + this._children = new List();
  49 + this._value = value;
  50 + }
  51 +
  52 + getValue(): any {
  53 + return this._value;
  54 + }
  55 +
  56 + getParent(): ?NavigationTreeNode {
  57 + return this.__parent;
  58 + }
  59 +
  60 + getChildrenCount(): number {
  61 + return this._children.size;
  62 + }
  63 +
  64 + getChildAt(index: number): ?NavigationTreeNode {
  65 + return index > -1 && index < this._children.size ?
  66 + this._children.get(index) :
  67 + null;
  68 + }
  69 +
  70 + appendChild(child: NavigationTreeNode): void {
  71 + if (child.__parent) {
  72 + child.__parent.removeChild(child);
  73 + }
  74 + child.__parent = this;
  75 + this._children = this._children.push(child);
  76 + }
  77 +
  78 + removeChild(child: NavigationTreeNode): void {
  79 + var index = this._children.indexOf(child);
  80 +
  81 + invariant(
  82 + index > -1,
  83 + 'The node to be removed is not a child of this node.'
  84 + );
  85 +
  86 + child.__parent = null;
  87 +
  88 + this._children = this._children.splice(index, 1);
  89 + }
  90 +
  91 + indexOf(child: NavigationTreeNode): number {
  92 + return this._children.indexOf(child);
  93 + }
  94 +
  95 + forEach(callback: Function, context: any): void {
  96 + this._children.forEach(callback, context);
  97 + }
  98 +
  99 + map(callback: Function, context: any): Array<NavigationTreeNode> {
  100 + return this._children.map(callback, context).toJS();
  101 + }
  102 +
  103 + some(callback: Function, context: any): boolean {
  104 + return this._children.some(callback, context);
  105 + }
  106 +}
  107 +
  108 +
  109 +module.exports = NavigationTreeNode;
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
  1 +/**
  2 + * Copyright (c) 2015, Facebook, Inc. All rights reserved.
  3 + *
  4 + * Facebook, Inc. ("Facebook") owns all right, title and interest, including
  5 + * all intellectual property and other proprietary rights, in and to the React
  6 + * Native CustomComponents software (the "Software"). Subject to your
  7 + * compliance with these terms, you are hereby granted a non-exclusive,
  8 + * worldwide, royalty-free copyright license to (1) use and copy the Software;
  9 + * and (2) reproduce and distribute the Software as part of your own software
  10 + * ("Your Software"). Facebook reserves all rights not expressly granted to
  11 + * you in this license agreement.
  12 + *
  13 + * THE SOFTWARE AND DOCUMENTATION, IF ANY, ARE PROVIDED "AS IS" AND ANY EXPRESS
  14 + * OR IMPLIED WARRANTIES (INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  15 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE) ARE DISCLAIMED.
  16 + * IN NO EVENT SHALL FACEBOOK OR ITS AFFILIATES, OFFICERS, DIRECTORS OR
  17 + * EMPLOYEES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  18 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  19 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  20 + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  21 + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  22 + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE SOFTWARE, EVEN IF
  23 + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  24 + *
  25 + */
  26 +'use strict';
  27 +
  28 +var NavigatorNavigationBarStylesAndroid = require('./NavigatorNavigationBarStylesAndroid');
  29 +
  30 +var buildStyleInterpolator = require('./buildStyleInterpolator');
  31 +var merge = require('./merge');
  32 +
  33 +var NAV_BAR_HEIGHT = NavigatorNavigationBarStylesAndroid.General.NavBarHeight;
  34 +
  35 +var SPACING = 8;
  36 +var ICON_WIDTH = 40;
  37 +var SEPARATOR_WIDTH = 9;
  38 +var CRUMB_WIDTH = ICON_WIDTH + SEPARATOR_WIDTH;
  39 +var NAV_ELEMENT_HEIGHT = NAV_BAR_HEIGHT;
  40 +
  41 +var OPACITY_RATIO = 100;
  42 +var ICON_INACTIVE_OPACITY = 0.6;
  43 +var MAX_BREADCRUMBS = 10;
  44 +
  45 +var CRUMB_BASE = {
  46 + position: 'absolute',
  47 + flexDirection: 'row',
  48 + top: 0,
  49 + width: CRUMB_WIDTH,
  50 + height: NAV_ELEMENT_HEIGHT,
  51 + backgroundColor: 'transparent',
  52 +};
  53 +
  54 +var ICON_BASE = {
  55 + width: ICON_WIDTH,
  56 + height: NAV_ELEMENT_HEIGHT,
  57 +};
  58 +
  59 +var SEPARATOR_BASE = {
  60 + width: SEPARATOR_WIDTH,
  61 + height: NAV_ELEMENT_HEIGHT,
  62 +};
  63 +
  64 +var TITLE_BASE = {
  65 + position: 'absolute',
  66 + top: 0,
  67 + height: NAV_ELEMENT_HEIGHT,
  68 + backgroundColor: 'transparent',
  69 + alignItems: 'flex-start',
  70 +};
  71 +
  72 +var FIRST_TITLE_BASE = merge(TITLE_BASE, {
  73 + left: 0,
  74 + right: 0,
  75 +});
  76 +
  77 +var RIGHT_BUTTON_BASE = {
  78 + position: 'absolute',
  79 + top: 0,
  80 + right: 0,
  81 + overflow: 'hidden',
  82 + opacity: 1,
  83 + height: NAV_ELEMENT_HEIGHT,
  84 + backgroundColor: 'transparent',
  85 +};
  86 +
  87 +/**
  88 + * Precompute crumb styles so that they don't need to be recomputed on every
  89 + * interaction.
  90 + */
  91 +var LEFT = [];
  92 +var CENTER = [];
  93 +var RIGHT = [];
  94 +for (var i = 0; i < MAX_BREADCRUMBS; i++) {
  95 + var crumbLeft = CRUMB_WIDTH * i + SPACING;
  96 + LEFT[i] = {
  97 + Crumb: merge(CRUMB_BASE, { left: crumbLeft }),
  98 + Icon: merge(ICON_BASE, { opacity: ICON_INACTIVE_OPACITY }),
  99 + Separator: merge(SEPARATOR_BASE, { opacity: 1 }),
  100 + Title: merge(TITLE_BASE, { left: crumbLeft, opacity: 0 }),
  101 + RightItem: merge(RIGHT_BUTTON_BASE, { opacity: 0 }),
  102 + };
  103 + CENTER[i] = {
  104 + Crumb: merge(CRUMB_BASE, { left: crumbLeft }),
  105 + Icon: merge(ICON_BASE, { opacity: 1 }),
  106 + Separator: merge(SEPARATOR_BASE, { opacity: 0 }),
  107 + Title: merge(TITLE_BASE, {
  108 + left: crumbLeft + ICON_WIDTH,
  109 + opacity: 1,
  110 + }),
  111 + RightItem: merge(RIGHT_BUTTON_BASE, { opacity: 1 }),
  112 + };
  113 + var crumbRight = crumbLeft + 50;
  114 + RIGHT[i] = {
  115 + Crumb: merge(CRUMB_BASE, { left: crumbRight}),
  116 + Icon: merge(ICON_BASE, { opacity: 0 }),
  117 + Separator: merge(SEPARATOR_BASE, { opacity: 0 }),
  118 + Title: merge(TITLE_BASE, {
  119 + left: crumbRight + ICON_WIDTH,
  120 + opacity: 0,
  121 + }),
  122 + RightItem: merge(RIGHT_BUTTON_BASE, { opacity: 0 }),
  123 + };
  124 +}
  125 +
  126 +// Special case the CENTER state of the first scene.
  127 +CENTER[0] = {
  128 + Crumb: merge(CRUMB_BASE, {left: SPACING + CRUMB_WIDTH}),
  129 + Icon: merge(ICON_BASE, {opacity: 0}),
  130 + Separator: merge(SEPARATOR_BASE, {opacity: 0}),
  131 + Title: merge(FIRST_TITLE_BASE, {opacity: 1}),
  132 + RightItem: CENTER[0].RightItem,
  133 +};
  134 +LEFT[0].Title = merge(FIRST_TITLE_BASE, {opacity: 0});
  135 +RIGHT[0].Title = merge(FIRST_TITLE_BASE, {opacity: 0});
  136 +
  137 +
  138 +var buildIndexSceneInterpolator = function(startStyles, endStyles) {
  139 + return {
  140 + Crumb: buildStyleInterpolator({
  141 + left: {
  142 + type: 'linear',
  143 + from: startStyles.Crumb.left,
  144 + to: endStyles.Crumb.left,
  145 + min: 0,
  146 + max: 1,
  147 + extrapolate: true,
  148 + },
  149 + }),
  150 + Icon: buildStyleInterpolator({
  151 + opacity: {
  152 + type: 'linear',
  153 + from: startStyles.Icon.opacity,
  154 + to: endStyles.Icon.opacity,
  155 + min: 0,
  156 + max: 1,
  157 + },
  158 + }),
  159 + Separator: buildStyleInterpolator({
  160 + opacity: {
  161 + type: 'linear',
  162 + from: startStyles.Separator.opacity,
  163 + to: endStyles.Separator.opacity,
  164 + min: 0,
  165 + max: 1,
  166 + },
  167 + }),
  168 + Title: buildStyleInterpolator({
  169 + opacity: {
  170 + type: 'linear',
  171 + from: startStyles.Title.opacity,
  172 + to: endStyles.Title.opacity,
  173 + min: 0,
  174 + max: 1,
  175 + },
  176 + left: {
  177 + type: 'linear',
  178 + from: startStyles.Title.left,
  179 + to: endStyles.Title.left,
  180 + min: 0,
  181 + max: 1,
  182 + extrapolate: true,
  183 + },
  184 + }),
  185 + RightItem: buildStyleInterpolator({
  186 + opacity: {
  187 + type: 'linear',
  188 + from: startStyles.RightItem.opacity,
  189 + to: endStyles.RightItem.opacity,
  190 + min: 0,
  191 + max: 1,
  192 + round: OPACITY_RATIO,
  193 + },
  194 + }),
  195 + };
  196 +};
  197 +
  198 +var Interpolators = CENTER.map(function(_, ii) {
  199 + return {
  200 + // Animating *into* the center stage from the right
  201 + RightToCenter: buildIndexSceneInterpolator(RIGHT[ii], CENTER[ii]),
  202 + // Animating out of the center stage, to the left
  203 + CenterToLeft: buildIndexSceneInterpolator(CENTER[ii], LEFT[ii]),
  204 + // Both stages (animating *past* the center stage)
  205 + RightToLeft: buildIndexSceneInterpolator(RIGHT[ii], LEFT[ii]),
  206 + };
  207 +});
  208 +
  209 +/**
  210 + * Contains constants that are used in constructing both `StyleSheet`s and
  211 + * inline styles during transitions.
  212 + */
  213 +module.exports = {
  214 + Interpolators,
  215 + Left: LEFT,
  216 + Center: CENTER,
  217 + Right: RIGHT,
  218 + IconWidth: ICON_WIDTH,
  219 + IconHeight: NAV_BAR_HEIGHT,
  220 + SeparatorWidth: SEPARATOR_WIDTH,
  221 + SeparatorHeight: NAV_BAR_HEIGHT,
  222 +};
  1 +/**
  2 + * Copyright (c) 2015, Facebook, Inc. All rights reserved.
  3 + *
  4 + * Facebook, Inc. ("Facebook") owns all right, title and interest, including
  5 + * all intellectual property and other proprietary rights, in and to the React
  6 + * Native CustomComponents software (the "Software"). Subject to your
  7 + * compliance with these terms, you are hereby granted a non-exclusive,
  8 + * worldwide, royalty-free copyright license to (1) use and copy the Software;
  9 + * and (2) reproduce and distribute the Software as part of your own software
  10 + * ("Your Software"). Facebook reserves all rights not expressly granted to
  11 + * you in this license agreement.
  12 + *
  13 + * THE SOFTWARE AND DOCUMENTATION, IF ANY, ARE PROVIDED "AS IS" AND ANY EXPRESS
  14 + * OR IMPLIED WARRANTIES (INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  15 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE) ARE DISCLAIMED.
  16 + * IN NO EVENT SHALL FACEBOOK OR ITS AFFILIATES, OFFICERS, DIRECTORS OR
  17 + * EMPLOYEES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  18 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  19 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  20 + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  21 + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  22 + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE SOFTWARE, EVEN IF
  23 + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  24 + *
  25 + */
  26 +'use strict';
  27 +
  28 +import {Dimensions} from 'react-native';
  29 +var NavigatorNavigationBarStylesIOS = require('./NavigatorNavigationBarStylesIOS');
  30 +
  31 +var buildStyleInterpolator = require('./buildStyleInterpolator');
  32 +var merge = require('./merge');
  33 +
  34 +var SCREEN_WIDTH = Dimensions.get('window').width;
  35 +var STATUS_BAR_HEIGHT = NavigatorNavigationBarStylesIOS.General.StatusBarHeight;
  36 +var NAV_BAR_HEIGHT = NavigatorNavigationBarStylesIOS.General.NavBarHeight;
  37 +
  38 +var SPACING = 4;
  39 +var ICON_WIDTH = 40;
  40 +var SEPARATOR_WIDTH = 9;
  41 +var CRUMB_WIDTH = ICON_WIDTH + SEPARATOR_WIDTH;
  42 +
  43 +var OPACITY_RATIO = 100;
  44 +var ICON_INACTIVE_OPACITY = 0.6;
  45 +var MAX_BREADCRUMBS = 10;
  46 +
  47 +var CRUMB_BASE = {
  48 + position: 'absolute',
  49 + flexDirection: 'row',
  50 + top: STATUS_BAR_HEIGHT,
  51 + width: CRUMB_WIDTH,
  52 + height: NAV_BAR_HEIGHT,
  53 + backgroundColor: 'transparent',
  54 +};
  55 +
  56 +var ICON_BASE = {
  57 + width: ICON_WIDTH,
  58 + height: NAV_BAR_HEIGHT,
  59 +};
  60 +
  61 +var SEPARATOR_BASE = {
  62 + width: SEPARATOR_WIDTH,
  63 + height: NAV_BAR_HEIGHT,
  64 +};
  65 +
  66 +var TITLE_BASE = {
  67 + position: 'absolute',
  68 + top: STATUS_BAR_HEIGHT,
  69 + height: NAV_BAR_HEIGHT,
  70 + backgroundColor: 'transparent',
  71 +};
  72 +
  73 +// For first title styles, make sure first title is centered
  74 +var FIRST_TITLE_BASE = merge(TITLE_BASE, {
  75 + left: 0,
  76 + right: 0,
  77 + alignItems: 'center',
  78 + height: NAV_BAR_HEIGHT,
  79 +});
  80 +
  81 +var RIGHT_BUTTON_BASE = {
  82 + position: 'absolute',
  83 + top: STATUS_BAR_HEIGHT,
  84 + right: SPACING,
  85 + overflow: 'hidden',
  86 + opacity: 1,
  87 + height: NAV_BAR_HEIGHT,
  88 + backgroundColor: 'transparent',
  89 +};
  90 +
  91 +/**
  92 + * Precompute crumb styles so that they don't need to be recomputed on every
  93 + * interaction.
  94 + */
  95 +var LEFT = [];
  96 +var CENTER = [];
  97 +var RIGHT = [];
  98 +for (var i = 0; i < MAX_BREADCRUMBS; i++) {
  99 + var crumbLeft = CRUMB_WIDTH * i + SPACING;
  100 + LEFT[i] = {
  101 + Crumb: merge(CRUMB_BASE, { left: crumbLeft }),
  102 + Icon: merge(ICON_BASE, { opacity: ICON_INACTIVE_OPACITY }),
  103 + Separator: merge(SEPARATOR_BASE, { opacity: 1 }),
  104 + Title: merge(TITLE_BASE, { left: crumbLeft, opacity: 0 }),
  105 + RightItem: merge(RIGHT_BUTTON_BASE, { opacity: 0 }),
  106 + };
  107 + CENTER[i] = {
  108 + Crumb: merge(CRUMB_BASE, { left: crumbLeft }),
  109 + Icon: merge(ICON_BASE, { opacity: 1 }),
  110 + Separator: merge(SEPARATOR_BASE, { opacity: 0 }),
  111 + Title: merge(TITLE_BASE, {
  112 + left: crumbLeft + ICON_WIDTH,
  113 + opacity: 1,
  114 + }),
  115 + RightItem: merge(RIGHT_BUTTON_BASE, { opacity: 1 }),
  116 + };
  117 + var crumbRight = SCREEN_WIDTH - 100;
  118 + RIGHT[i] = {
  119 + Crumb: merge(CRUMB_BASE, { left: crumbRight}),
  120 + Icon: merge(ICON_BASE, { opacity: 0 }),
  121 + Separator: merge(SEPARATOR_BASE, { opacity: 0 }),
  122 + Title: merge(TITLE_BASE, {
  123 + left: crumbRight + ICON_WIDTH,
  124 + opacity: 0,
  125 + }),
  126 + RightItem: merge(RIGHT_BUTTON_BASE, { opacity: 0 }),
  127 + };
  128 +}
  129 +
  130 +// Special case the CENTER state of the first scene.
  131 +CENTER[0] = {
  132 + Crumb: merge(CRUMB_BASE, {left: SCREEN_WIDTH / 4}),
  133 + Icon: merge(ICON_BASE, {opacity: 0}),
  134 + Separator: merge(SEPARATOR_BASE, {opacity: 0}),
  135 + Title: merge(FIRST_TITLE_BASE, {opacity: 1}),
  136 + RightItem: CENTER[0].RightItem,
  137 +};
  138 +LEFT[0].Title = merge(FIRST_TITLE_BASE, {left: -SCREEN_WIDTH / 4, opacity: 0});
  139 +RIGHT[0].Title = merge(FIRST_TITLE_BASE, {opacity: 0});
  140 +
  141 +
  142 +var buildIndexSceneInterpolator = function(startStyles, endStyles) {
  143 + return {
  144 + Crumb: buildStyleInterpolator({
  145 + left: {
  146 + type: 'linear',
  147 + from: startStyles.Crumb.left,
  148 + to: endStyles.Crumb.left,
  149 + min: 0,
  150 + max: 1,
  151 + extrapolate: true,
  152 + },
  153 + }),
  154 + Icon: buildStyleInterpolator({
  155 + opacity: {
  156 + type: 'linear',
  157 + from: startStyles.Icon.opacity,
  158 + to: endStyles.Icon.opacity,
  159 + min: 0,
  160 + max: 1,
  161 + },
  162 + }),
  163 + Separator: buildStyleInterpolator({
  164 + opacity: {
  165 + type: 'linear',
  166 + from: startStyles.Separator.opacity,
  167 + to: endStyles.Separator.opacity,
  168 + min: 0,
  169 + max: 1,
  170 + },
  171 + }),
  172 + Title: buildStyleInterpolator({
  173 + opacity: {
  174 + type: 'linear',
  175 + from: startStyles.Title.opacity,
  176 + to: endStyles.Title.opacity,
  177 + min: 0,
  178 + max: 1,
  179 + },
  180 + left: {
  181 + type: 'linear',
  182 + from: startStyles.Title.left,
  183 + to: endStyles.Title.left,
  184 + min: 0,
  185 + max: 1,
  186 + extrapolate: true,
  187 + },
  188 + }),
  189 + RightItem: buildStyleInterpolator({
  190 + opacity: {
  191 + type: 'linear',
  192 + from: startStyles.RightItem.opacity,
  193 + to: endStyles.RightItem.opacity,
  194 + min: 0,
  195 + max: 1,
  196 + round: OPACITY_RATIO,
  197 + },
  198 + }),
  199 + };
  200 +};
  201 +
  202 +var Interpolators = CENTER.map(function(_, ii) {
  203 + return {
  204 + // Animating *into* the center stage from the right
  205 + RightToCenter: buildIndexSceneInterpolator(RIGHT[ii], CENTER[ii]),
  206 + // Animating out of the center stage, to the left
  207 + CenterToLeft: buildIndexSceneInterpolator(CENTER[ii], LEFT[ii]),
  208 + // Both stages (animating *past* the center stage)
  209 + RightToLeft: buildIndexSceneInterpolator(RIGHT[ii], LEFT[ii]),
  210 + };
  211 +});
  212 +
  213 +/**
  214 + * Contains constants that are used in constructing both `StyleSheet`s and
  215 + * inline styles during transitions.
  216 + */
  217 +module.exports = {
  218 + Interpolators,
  219 + Left: LEFT,
  220 + Center: CENTER,
  221 + Right: RIGHT,
  222 + IconWidth: ICON_WIDTH,
  223 + IconHeight: NAV_BAR_HEIGHT,
  224 + SeparatorWidth: SEPARATOR_WIDTH,
  225 + SeparatorHeight: NAV_BAR_HEIGHT,
  226 +};
  1 +/**
  2 + * Copyright (c) 2015, Facebook, Inc. All rights reserved.
  3 + *
  4 + * Facebook, Inc. ("Facebook") owns all right, title and interest, including
  5 + * all intellectual property and other proprietary rights, in and to the React
  6 + * Native CustomComponents software (the "Software"). Subject to your
  7 + * compliance with these terms, you are hereby granted a non-exclusive,
  8 + * worldwide, royalty-free copyright license to (1) use and copy the Software;
  9 + * and (2) reproduce and distribute the Software as part of your own software
  10 + * ("Your Software"). Facebook reserves all rights not expressly granted to
  11 + * you in this license agreement.
  12 + *
  13 + * THE SOFTWARE AND DOCUMENTATION, IF ANY, ARE PROVIDED "AS IS" AND ANY EXPRESS
  14 + * OR IMPLIED WARRANTIES (INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  15 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE) ARE DISCLAIMED.
  16 + * IN NO EVENT SHALL FACEBOOK OR ITS AFFILIATES, OFFICERS, DIRECTORS OR
  17 + * EMPLOYEES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  18 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  19 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  20 + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  21 + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  22 + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE SOFTWARE, EVEN IF
  23 + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  24 + *
  25 + */
  26 +'use strict';
  27 +
  28 +var React = require('react');
  29 +var NavigatorNavigationBarStylesAndroid = require('./NavigatorNavigationBarStylesAndroid');
  30 +var NavigatorNavigationBarStylesIOS = require('./NavigatorNavigationBarStylesIOS');
  31 +import {
  32 + Platform,
  33 + StyleSheet,
  34 + View,
  35 + ViewPropTypes,
  36 +} from 'react-native';
  37 +var PropTypes = require('prop-types');
  38 +
  39 +var guid = require('./guid');
  40 +
  41 +var { Map } = require('immutable');
  42 +
  43 +var COMPONENT_NAMES = ['Title', 'LeftButton', 'RightButton'];
  44 +
  45 +var NavigatorNavigationBarStyles = Platform.OS === 'android' ?
  46 + NavigatorNavigationBarStylesAndroid : NavigatorNavigationBarStylesIOS;
  47 +
  48 +var navStatePresentedIndex = function(navState) {
  49 + if (navState.presentedIndex !== undefined) {
  50 + return navState.presentedIndex;
  51 + }
  52 + // TODO: rename `observedTopOfStack` to `presentedIndex` in `NavigatorIOS`
  53 + return navState.observedTopOfStack;
  54 +};
  55 +
  56 +class NavigatorNavigationBar extends React.Component {
  57 + static propTypes = {
  58 + navigator: PropTypes.object,
  59 + routeMapper: PropTypes.shape({
  60 + Title: PropTypes.func.isRequired,
  61 + LeftButton: PropTypes.func.isRequired,
  62 + RightButton: PropTypes.func.isRequired,
  63 + }).isRequired,
  64 + navState: PropTypes.shape({
  65 + routeStack: PropTypes.arrayOf(PropTypes.object),
  66 + presentedIndex: PropTypes.number,
  67 + }),
  68 + navigationStyles: PropTypes.object,
  69 + style: ViewPropTypes.style,
  70 + };
  71 +
  72 + static Styles = NavigatorNavigationBarStyles;
  73 + static StylesAndroid = NavigatorNavigationBarStylesAndroid;
  74 + static StylesIOS = NavigatorNavigationBarStylesIOS;
  75 +
  76 + static defaultProps = {
  77 + navigationStyles: NavigatorNavigationBarStyles,
  78 + };
  79 +
  80 + componentWillMount() {
  81 + this._reset();
  82 + }
  83 +
  84 + /**
  85 + * Stop transtion, immediately resets the cached state and re-render the
  86 + * whole view.
  87 + */
  88 + immediatelyRefresh = () => {
  89 + this._reset();
  90 + this.forceUpdate();
  91 + };
  92 +
  93 + _reset = () => {
  94 + this._key = guid();
  95 + this._reusableProps = {};
  96 + this._components = {};
  97 + this._descriptors = {};
  98 +
  99 + COMPONENT_NAMES.forEach(componentName => {
  100 + this._components[componentName] = new Map();
  101 + this._descriptors[componentName] = new Map();
  102 + });
  103 + };
  104 +
  105 + _getReusableProps = (/*string*/componentName, /*number*/index) => /*object*/ {
  106 + var propStack = this._reusableProps[componentName];
  107 + if (!propStack) {
  108 + propStack = this._reusableProps[componentName] = [];
  109 + }
  110 + var props = propStack[index];
  111 + if (!props) {
  112 + props = propStack[index] = {style:{}};
  113 + }
  114 + return props;
  115 + };
  116 +
  117 + _updateIndexProgress = (
  118 + /*number*/progress,
  119 + /*number*/index,
  120 + /*number*/fromIndex,
  121 + /*number*/toIndex,
  122 + ) => {
  123 + var amount = toIndex > fromIndex ? progress : (1 - progress);
  124 + var oldDistToCenter = index - fromIndex;
  125 + var newDistToCenter = index - toIndex;
  126 + var interpolate;
  127 + if (oldDistToCenter > 0 && newDistToCenter === 0 ||
  128 + newDistToCenter > 0 && oldDistToCenter === 0) {
  129 + interpolate = this.props.navigationStyles.Interpolators.RightToCenter;
  130 + } else if (oldDistToCenter < 0 && newDistToCenter === 0 ||
  131 + newDistToCenter < 0 && oldDistToCenter === 0) {
  132 + interpolate = this.props.navigationStyles.Interpolators.CenterToLeft;
  133 + } else if (oldDistToCenter === newDistToCenter) {
  134 + interpolate = this.props.navigationStyles.Interpolators.RightToCenter;
  135 + } else {
  136 + interpolate = this.props.navigationStyles.Interpolators.RightToLeft;
  137 + }
  138 +
  139 + COMPONENT_NAMES.forEach(function (componentName) {
  140 + var component = this._components[componentName].get(this.props.navState.routeStack[index]);
  141 + var props = this._getReusableProps(componentName, index);
  142 + if (component && interpolate[componentName](props.style, amount)) {
  143 + props.pointerEvents = props.style.opacity === 0 ? 'none' : 'box-none';
  144 + component.setNativeProps(props);
  145 + }
  146 + }, this);
  147 + };
  148 +
  149 + updateProgress = (/*number*/progress, /*number*/fromIndex, /*number*/toIndex) => {
  150 + var max = Math.max(fromIndex, toIndex);
  151 + var min = Math.min(fromIndex, toIndex);
  152 + for (var index = min; index <= max; index++) {
  153 + this._updateIndexProgress(progress, index, fromIndex, toIndex);
  154 + }
  155 + };
  156 +
  157 + render() {
  158 + var navBarStyle = {
  159 + height: this.props.navigationStyles.General.TotalNavHeight,
  160 + };
  161 + var navState = this.props.navState;
  162 + var components = navState.routeStack.map((route, index) =>
  163 + COMPONENT_NAMES.map(componentName =>
  164 + this._getComponent(componentName, route, index)
  165 + )
  166 + );
  167 +
  168 + return (
  169 + <View
  170 + key={this._key}
  171 + style={[styles.navBarContainer, navBarStyle, this.props.style]}>
  172 + {components}
  173 + </View>
  174 + );
  175 + }
  176 +
  177 + _getComponent = (/*string*/componentName, /*object*/route, /*number*/index) => /*?Object*/ {
  178 + if (this._descriptors[componentName].includes(route)) {
  179 + return this._descriptors[componentName].get(route);
  180 + }
  181 +
  182 + var rendered = null;
  183 +
  184 + var content = this.props.routeMapper[componentName](
  185 + this.props.navState.routeStack[index],
  186 + this.props.navigator,
  187 + index,
  188 + this.props.navState
  189 + );
  190 + if (!content) {
  191 + return null;
  192 + }
  193 +
  194 + var componentIsActive = index === navStatePresentedIndex(this.props.navState);
  195 + var initialStage = componentIsActive ?
  196 + this.props.navigationStyles.Stages.Center :
  197 + this.props.navigationStyles.Stages.Left;
  198 + rendered = (
  199 + <View
  200 + ref={(ref) => {
  201 + this._components[componentName] = this._components[componentName].set(route, ref);
  202 + }}
  203 + pointerEvents={componentIsActive ? 'box-none' : 'none'}
  204 + style={initialStage[componentName]}>
  205 + {content}
  206 + </View>
  207 + );
  208 +
  209 + this._descriptors[componentName] = this._descriptors[componentName].set(route, rendered);
  210 + return rendered;
  211 + };
  212 +}
  213 +
  214 +
  215 +var styles = StyleSheet.create({
  216 + navBarContainer: {
  217 + position: 'absolute',
  218 + top: 0,
  219 + left: 0,
  220 + right: 0,
  221 + backgroundColor: 'transparent',
  222 + },
  223 +});
  224 +
  225 +module.exports = NavigatorNavigationBar;
  1 +/**
  2 + * Copyright (c) 2015, Facebook, Inc. All rights reserved.
  3 + *
  4 + * Facebook, Inc. ("Facebook") owns all right, title and interest, including
  5 + * all intellectual property and other proprietary rights, in and to the React
  6 + * Native CustomComponents software (the "Software"). Subject to your
  7 + * compliance with these terms, you are hereby granted a non-exclusive,
  8 + * worldwide, royalty-free copyright license to (1) use and copy the Software;
  9 + * and (2) reproduce and distribute the Software as part of your own software
  10 + * ("Your Software"). Facebook reserves all rights not expressly granted to
  11 + * you in this license agreement.
  12 + *
  13 + * THE SOFTWARE AND DOCUMENTATION, IF ANY, ARE PROVIDED "AS IS" AND ANY EXPRESS
  14 + * OR IMPLIED WARRANTIES (INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  15 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE) ARE DISCLAIMED.
  16 + * IN NO EVENT SHALL FACEBOOK OR ITS AFFILIATES, OFFICERS, DIRECTORS OR
  17 + * EMPLOYEES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  18 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  19 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  20 + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  21 + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  22 + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE SOFTWARE, EVEN IF
  23 + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  24 + *
  25 + */
  26 +'use strict';
  27 +
  28 +var buildStyleInterpolator = require('./buildStyleInterpolator');
  29 +var merge = require('./merge');
  30 +
  31 +// Android Material Design
  32 +var NAV_BAR_HEIGHT = 56;
  33 +var TITLE_LEFT = 72;
  34 +var BUTTON_SIZE = 24;
  35 +var TOUCH_TARGT_SIZE = 48;
  36 +var BUTTON_HORIZONTAL_MARGIN = 16;
  37 +
  38 +var BUTTON_EFFECTIVE_MARGIN = BUTTON_HORIZONTAL_MARGIN - (TOUCH_TARGT_SIZE - BUTTON_SIZE) / 2;
  39 +var NAV_ELEMENT_HEIGHT = NAV_BAR_HEIGHT;
  40 +
  41 +var BASE_STYLES = {
  42 + Title: {
  43 + position: 'absolute',
  44 + bottom: 0,
  45 + left: 0,
  46 + right: 0,
  47 + alignItems: 'flex-start',
  48 + height: NAV_ELEMENT_HEIGHT,
  49 + backgroundColor: 'transparent',
  50 + marginLeft: TITLE_LEFT,
  51 + },
  52 + LeftButton: {
  53 + position: 'absolute',
  54 + top: 0,
  55 + left: BUTTON_EFFECTIVE_MARGIN,
  56 + overflow: 'hidden',
  57 + height: NAV_ELEMENT_HEIGHT,
  58 + backgroundColor: 'transparent',
  59 + },
  60 + RightButton: {
  61 + position: 'absolute',
  62 + top: 0,
  63 + right: BUTTON_EFFECTIVE_MARGIN,
  64 + overflow: 'hidden',
  65 + alignItems: 'flex-end',
  66 + height: NAV_ELEMENT_HEIGHT,
  67 + backgroundColor: 'transparent',
  68 + },
  69 +};
  70 +
  71 +// There are 3 stages: left, center, right. All previous navigation
  72 +// items are in the left stage. The current navigation item is in the
  73 +// center stage. All upcoming navigation items are in the right stage.
  74 +// Another way to think of the stages is in terms of transitions. When
  75 +// we move forward in the navigation stack, we perform a
  76 +// right-to-center transition on the new navigation item and a
  77 +// center-to-left transition on the current navigation item.
  78 +var Stages = {
  79 + Left: {
  80 + Title: merge(BASE_STYLES.Title, { opacity: 0 }),
  81 + LeftButton: merge(BASE_STYLES.LeftButton, { opacity: 0 }),
  82 + RightButton: merge(BASE_STYLES.RightButton, { opacity: 0 }),
  83 + },
  84 + Center: {
  85 + Title: merge(BASE_STYLES.Title, { opacity: 1 }),
  86 + LeftButton: merge(BASE_STYLES.LeftButton, { opacity: 1 }),
  87 + RightButton: merge(BASE_STYLES.RightButton, { opacity: 1 }),
  88 + },
  89 + Right: {
  90 + Title: merge(BASE_STYLES.Title, { opacity: 0 }),
  91 + LeftButton: merge(BASE_STYLES.LeftButton, { opacity: 0 }),
  92 + RightButton: merge(BASE_STYLES.RightButton, { opacity: 0 }),
  93 + },
  94 +};
  95 +
  96 +
  97 +var opacityRatio = 100;
  98 +
  99 +function buildSceneInterpolators(startStyles, endStyles) {
  100 + return {
  101 + Title: buildStyleInterpolator({
  102 + opacity: {
  103 + type: 'linear',
  104 + from: startStyles.Title.opacity,
  105 + to: endStyles.Title.opacity,
  106 + min: 0,
  107 + max: 1,
  108 + },
  109 + left: {
  110 + type: 'linear',
  111 + from: startStyles.Title.left,
  112 + to: endStyles.Title.left,
  113 + min: 0,
  114 + max: 1,
  115 + extrapolate: true,
  116 + },
  117 + }),
  118 + LeftButton: buildStyleInterpolator({
  119 + opacity: {
  120 + type: 'linear',
  121 + from: startStyles.LeftButton.opacity,
  122 + to: endStyles.LeftButton.opacity,
  123 + min: 0,
  124 + max: 1,
  125 + round: opacityRatio,
  126 + },
  127 + left: {
  128 + type: 'linear',
  129 + from: startStyles.LeftButton.left,
  130 + to: endStyles.LeftButton.left,
  131 + min: 0,
  132 + max: 1,
  133 + },
  134 + }),
  135 + RightButton: buildStyleInterpolator({
  136 + opacity: {
  137 + type: 'linear',
  138 + from: startStyles.RightButton.opacity,
  139 + to: endStyles.RightButton.opacity,
  140 + min: 0,
  141 + max: 1,
  142 + round: opacityRatio,
  143 + },
  144 + left: {
  145 + type: 'linear',
  146 + from: startStyles.RightButton.left,
  147 + to: endStyles.RightButton.left,
  148 + min: 0,
  149 + max: 1,
  150 + extrapolate: true,
  151 + },
  152 + }),
  153 + };
  154 +}
  155 +
  156 +var Interpolators = {
  157 + // Animating *into* the center stage from the right
  158 + RightToCenter: buildSceneInterpolators(Stages.Right, Stages.Center),
  159 + // Animating out of the center stage, to the left
  160 + CenterToLeft: buildSceneInterpolators(Stages.Center, Stages.Left),
  161 + // Both stages (animating *past* the center stage)
  162 + RightToLeft: buildSceneInterpolators(Stages.Right, Stages.Left),
  163 +};
  164 +
  165 +
  166 +module.exports = {
  167 + General: {
  168 + NavBarHeight: NAV_BAR_HEIGHT,
  169 + StatusBarHeight: 0,
  170 + TotalNavHeight: NAV_BAR_HEIGHT,
  171 + },
  172 + Interpolators,
  173 + Stages,
  174 +};
  1 +/**
  2 + * Copyright (c) 2015, Facebook, Inc. All rights reserved.
  3 + *
  4 + * Facebook, Inc. ("Facebook") owns all right, title and interest, including
  5 + * all intellectual property and other proprietary rights, in and to the React
  6 + * Native CustomComponents software (the "Software"). Subject to your
  7 + * compliance with these terms, you are hereby granted a non-exclusive,
  8 + * worldwide, royalty-free copyright license to (1) use and copy the Software;
  9 + * and (2) reproduce and distribute the Software as part of your own software
  10 + * ("Your Software"). Facebook reserves all rights not expressly granted to
  11 + * you in this license agreement.
  12 + *
  13 + * THE SOFTWARE AND DOCUMENTATION, IF ANY, ARE PROVIDED "AS IS" AND ANY EXPRESS
  14 + * OR IMPLIED WARRANTIES (INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  15 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE) ARE DISCLAIMED.
  16 + * IN NO EVENT SHALL FACEBOOK OR ITS AFFILIATES, OFFICERS, DIRECTORS OR
  17 + * EMPLOYEES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  18 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  19 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  20 + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  21 + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  22 + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE SOFTWARE, EVEN IF
  23 + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  24 + *
  25 + */
  26 +'use strict';
  27 +
  28 +import {
  29 + Dimensions,
  30 + I18nManager,
  31 + PixelRatio,
  32 +} from 'react-native';
  33 +
  34 +var buildStyleInterpolator = require('./buildStyleInterpolator');
  35 +var merge = require('./merge');
  36 +
  37 +var SCREEN_WIDTH = Dimensions.get('window').width;
  38 +var NAV_BAR_HEIGHT = 44;
  39 +var STATUS_BAR_HEIGHT = 20;
  40 +var NAV_HEIGHT = NAV_BAR_HEIGHT + STATUS_BAR_HEIGHT;
  41 +
  42 +var BASE_STYLES = {
  43 + Title: {
  44 + position: 'absolute',
  45 + top: STATUS_BAR_HEIGHT,
  46 + left: 0,
  47 + right: 0,
  48 + alignItems: 'center',
  49 + height: NAV_BAR_HEIGHT,
  50 + backgroundColor: 'transparent',
  51 + },
  52 + LeftButton: {
  53 + position: 'absolute',
  54 + top: STATUS_BAR_HEIGHT,
  55 + left: 0,
  56 + overflow: 'hidden',
  57 + opacity: 1,
  58 + height: NAV_BAR_HEIGHT,
  59 + backgroundColor: 'transparent',
  60 + },
  61 + RightButton: {
  62 + position: 'absolute',
  63 + top: STATUS_BAR_HEIGHT,
  64 + right: 0,
  65 + overflow: 'hidden',
  66 + opacity: 1,
  67 + alignItems: 'flex-end',
  68 + height: NAV_BAR_HEIGHT,
  69 + backgroundColor: 'transparent',
  70 + },
  71 +};
  72 +
  73 +// There are 3 stages: left, center, right. All previous navigation
  74 +// items are in the left stage. The current navigation item is in the
  75 +// center stage. All upcoming navigation items are in the right stage.
  76 +// Another way to think of the stages is in terms of transitions. When
  77 +// we move forward in the navigation stack, we perform a
  78 +// right-to-center transition on the new navigation item and a
  79 +// center-to-left transition on the current navigation item.
  80 +var Stages = {
  81 + Left: {
  82 + Title: merge(BASE_STYLES.Title, { left: -SCREEN_WIDTH / 2, opacity: 0 }),
  83 + LeftButton: merge(BASE_STYLES.LeftButton, { left: 0, opacity: 0 }),
  84 + RightButton: merge(BASE_STYLES.RightButton, { opacity: 0 }),
  85 + },
  86 + Center: {
  87 + Title: merge(BASE_STYLES.Title, { left: 0, opacity: 1 }),
  88 + LeftButton: merge(BASE_STYLES.LeftButton, { left: 0, opacity: 1 }),
  89 + RightButton: merge(BASE_STYLES.RightButton, { opacity: 1 }),
  90 + },
  91 + Right: {
  92 + Title: merge(BASE_STYLES.Title, { left: SCREEN_WIDTH / 2, opacity: 0 }),
  93 + LeftButton: merge(BASE_STYLES.LeftButton, { left: 0, opacity: 0 }),
  94 + RightButton: merge(BASE_STYLES.RightButton, { opacity: 0 }),
  95 + },
  96 +};
  97 +
  98 +
  99 +var opacityRatio = 100;
  100 +
  101 +function buildSceneInterpolators(startStyles, endStyles) {
  102 + return {
  103 + Title: buildStyleInterpolator({
  104 + opacity: {
  105 + type: 'linear',
  106 + from: startStyles.Title.opacity,
  107 + to: endStyles.Title.opacity,
  108 + min: 0,
  109 + max: 1,
  110 + },
  111 + left: {
  112 + type: 'linear',
  113 + from: startStyles.Title.left,
  114 + to: endStyles.Title.left,
  115 + min: 0,
  116 + max: 1,
  117 + extrapolate: true,
  118 + },
  119 + }),
  120 + LeftButton: buildStyleInterpolator({
  121 + opacity: {
  122 + type: 'linear',
  123 + from: startStyles.LeftButton.opacity,
  124 + to: endStyles.LeftButton.opacity,
  125 + min: 0,
  126 + max: 1,
  127 + round: opacityRatio,
  128 + },
  129 + left: {
  130 + type: 'linear',
  131 + from: startStyles.LeftButton.left,
  132 + to: endStyles.LeftButton.left,
  133 + min: 0,
  134 + max: 1,
  135 + },
  136 + }),
  137 + RightButton: buildStyleInterpolator({
  138 + opacity: {
  139 + type: 'linear',
  140 + from: startStyles.RightButton.opacity,
  141 + to: endStyles.RightButton.opacity,
  142 + min: 0,
  143 + max: 1,
  144 + round: opacityRatio,
  145 + },
  146 + left: {
  147 + type: 'linear',
  148 + from: startStyles.RightButton.left,
  149 + to: endStyles.RightButton.left,
  150 + min: 0,
  151 + max: 1,
  152 + extrapolate: true,
  153 + },
  154 + }),
  155 + };
  156 +}
  157 +
  158 +var Interpolators = {
  159 + // Animating *into* the center stage from the right
  160 + RightToCenter: buildSceneInterpolators(Stages.Right, Stages.Center),
  161 + // Animating out of the center stage, to the left
  162 + CenterToLeft: buildSceneInterpolators(Stages.Center, Stages.Left),
  163 + // Both stages (animating *past* the center stage)
  164 + RightToLeft: buildSceneInterpolators(Stages.Right, Stages.Left),
  165 +};
  166 +
  167 +
  168 +module.exports = {
  169 + General: {
  170 + NavBarHeight: NAV_BAR_HEIGHT,
  171 + StatusBarHeight: STATUS_BAR_HEIGHT,
  172 + TotalNavHeight: NAV_HEIGHT,
  173 + },
  174 + Interpolators,
  175 + Stages,
  176 +};
This diff is collapsed. Click to expand it.
  1 +/**
  2 + * Copyright (c) 2015, Facebook, Inc. All rights reserved.
  3 + *
  4 + * Facebook, Inc. ("Facebook") owns all right, title and interest, including
  5 + * all intellectual property and other proprietary rights, in and to the React
  6 + * Native CustomComponents software (the "Software"). Subject to your
  7 + * compliance with these terms, you are hereby granted a non-exclusive,
  8 + * worldwide, royalty-free copyright license to (1) use and copy the Software;
  9 + * and (2) reproduce and distribute the Software as part of your own software
  10 + * ("Your Software"). Facebook reserves all rights not expressly granted to
  11 + * you in this license agreement.
  12 + *
  13 + * THE SOFTWARE AND DOCUMENTATION, IF ANY, ARE PROVIDED "AS IS" AND ANY EXPRESS
  14 + * OR IMPLIED WARRANTIES (INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  15 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE) ARE DISCLAIMED.
  16 + * IN NO EVENT SHALL FACEBOOK OR ITS AFFILIATES, OFFICERS, DIRECTORS OR
  17 + * EMPLOYEES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  18 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  19 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  20 + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  21 + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  22 + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE SOFTWARE, EVEN IF
  23 + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  24 + *
  25 + * @flow
  26 + */
  27 +'use strict';
  28 +
  29 +import type EventEmitter from './EventEmitter';
  30 +
  31 +/**
  32 + * Subscribable provides a mixin for safely subscribing a component to an
  33 + * eventEmitter
  34 + *
  35 + * This will be replaced with the observe interface that will be coming soon to
  36 + * React Core
  37 + */
  38 +
  39 +var Subscribable = {};
  40 +
  41 +Subscribable.Mixin = {
  42 +
  43 + componentWillMount: function() {
  44 + this._subscribableSubscriptions = [];
  45 + },
  46 +
  47 + componentWillUnmount: function() {
  48 + this._subscribableSubscriptions.forEach(
  49 + (subscription) => subscription.remove()
  50 + );
  51 + this._subscribableSubscriptions = null;
  52 + },
  53 +
  54 + /**
  55 + * Special form of calling `addListener` that *guarantees* that a
  56 + * subscription *must* be tied to a component instance, and therefore will
  57 + * be cleaned up when the component is unmounted. It is impossible to create
  58 + * the subscription and pass it in - this method must be the one to create
  59 + * the subscription and therefore can guarantee it is retained in a way that
  60 + * will be cleaned up.
  61 + *
  62 + * @param {EventEmitter} eventEmitter emitter to subscribe to.
  63 + * @param {string} eventType Type of event to listen to.
  64 + * @param {function} listener Function to invoke when event occurs.
  65 + * @param {object} context Object to use as listener context.
  66 + */
  67 + addListenerOn: function(
  68 + eventEmitter: EventEmitter,
  69 + eventType: string,
  70 + listener: Function,
  71 + context: Object
  72 + ) {
  73 + this._subscribableSubscriptions.push(
  74 + eventEmitter.addListener(eventType, listener, context)
  75 + );
  76 + }
  77 +};
  78 +
  79 +module.exports = Subscribable;
  1 +/**
  2 + * Copyright (c) 2015, Facebook, Inc. All rights reserved.
  3 + *
  4 + * Facebook, Inc. ("Facebook") owns all right, title and interest, including
  5 + * all intellectual property and other proprietary rights, in and to the React
  6 + * Native CustomComponents software (the "Software"). Subject to your
  7 + * compliance with these terms, you are hereby granted a non-exclusive,
  8 + * worldwide, royalty-free copyright license to (1) use and copy the Software;
  9 + * and (2) reproduce and distribute the Software as part of your own software
  10 + * ("Your Software"). Facebook reserves all rights not expressly granted to
  11 + * you in this license agreement.
  12 + *
  13 + * THE SOFTWARE AND DOCUMENTATION, IF ANY, ARE PROVIDED "AS IS" AND ANY EXPRESS
  14 + * OR IMPLIED WARRANTIES (INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  15 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE) ARE DISCLAIMED.
  16 + * IN NO EVENT SHALL FACEBOOK OR ITS AFFILIATES, OFFICERS, DIRECTORS OR
  17 + * EMPLOYEES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  18 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  19 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  20 + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  21 + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  22 + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE SOFTWARE, EVEN IF
  23 + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  24 + */
  25 +'use strict';
  26 +
  27 +jest
  28 + .disableAutomock()
  29 + .mock('ErrorUtils');
  30 +
  31 +var NavigationContext = require('NavigationContext');
  32 +var NavigationEvent = require('NavigationEvent');
  33 +
  34 +describe('NavigationContext', () => {
  35 + it('defaults `currentRoute` to null', () => {
  36 + var context = new NavigationContext();
  37 + expect(context.currentRoute).toEqual(null);
  38 + });
  39 +
  40 + it('updates `currentRoute`', () => {
  41 + var context = new NavigationContext();
  42 + context.emit('didfocus', {route: {name: 'a'}});
  43 + expect(context.currentRoute.name).toEqual('a');
  44 + });
  45 +
  46 + it('has parent', () => {
  47 + var parent = new NavigationContext();
  48 + var child = new NavigationContext();
  49 + parent.appendChild(child);
  50 + expect(child.parent).toBe(parent);
  51 + });
  52 +
  53 + it('has `top`', () => {
  54 + var top = new NavigationContext();
  55 + var parent = new NavigationContext();
  56 + var child = new NavigationContext();
  57 + top.appendChild(parent);
  58 + parent.appendChild(child);
  59 + expect(child.top).toBe(top);
  60 + });
  61 +
  62 + it('captures event', () => {
  63 + var parent = new NavigationContext();
  64 + var child = new NavigationContext();
  65 + parent.appendChild(child);
  66 +
  67 + var logs = [];
  68 +
  69 + var listener = (event) => {
  70 + var {currentTarget, eventPhase, target, type} = event;
  71 + logs.push({
  72 + currentTarget,
  73 + eventPhase,
  74 + target,
  75 + type,
  76 + });
  77 + };
  78 +
  79 + parent.addListener('yo', listener, true);
  80 + child.addListener('yo', listener, true);
  81 +
  82 + child.emit('yo');
  83 +
  84 + expect(logs).toEqual([
  85 + {
  86 + currentTarget: parent,
  87 + eventPhase: NavigationEvent.CAPTURING_PHASE,
  88 + target: child,
  89 + type: 'yo',
  90 + },
  91 + {
  92 + currentTarget: child,
  93 + eventPhase: NavigationEvent.AT_TARGET,
  94 + target: child,
  95 + type: 'yo',
  96 + }
  97 + ]);
  98 + });
  99 +
  100 + it('bubbles events', () => {
  101 + var parent = new NavigationContext();
  102 + var child = new NavigationContext();
  103 + parent.appendChild(child);
  104 +
  105 + var logs = [];
  106 +
  107 + var listener = (event) => {
  108 + var {currentTarget, eventPhase, target, type} = event;
  109 + logs.push({
  110 + currentTarget,
  111 + eventPhase,
  112 + target,
  113 + type,
  114 + });
  115 + };
  116 +
  117 + parent.addListener('yo', listener);
  118 + child.addListener('yo', listener);
  119 +
  120 + child.emit('yo');
  121 +
  122 + expect(logs).toEqual([
  123 + {
  124 + currentTarget: child,
  125 + eventPhase: NavigationEvent.AT_TARGET,
  126 + target: child,
  127 + type: 'yo',
  128 + },
  129 + {
  130 + currentTarget: parent,
  131 + eventPhase: NavigationEvent.BUBBLING_PHASE,
  132 + target: child,
  133 + type: 'yo',
  134 + },
  135 + ]);
  136 + });
  137 +
  138 + it('stops event propagation at capture phase', () => {
  139 + var parent = new NavigationContext();
  140 + var child = new NavigationContext();
  141 + parent.appendChild(child);
  142 +
  143 + var counter = 0;
  144 +
  145 + parent.addListener('yo', event => event.stopPropagation(), true);
  146 + child.addListener('yo', event => counter++, true);
  147 +
  148 + child.emit('yo');
  149 +
  150 + expect(counter).toBe(0);
  151 + });
  152 +
  153 + it('stops event propagation at bubbling phase', () => {
  154 + var parent = new NavigationContext();
  155 + var child = new NavigationContext();
  156 + parent.appendChild(child);
  157 +
  158 + var counter = 0;
  159 +
  160 + parent.addListener('yo', event => counter++);
  161 + child.addListener('yo', event => event.stopPropagation());
  162 +
  163 + child.emit('yo');
  164 +
  165 + expect(counter).toBe(0);
  166 + });
  167 +
  168 + it('prevents event at capture phase', () => {
  169 + var parent = new NavigationContext();
  170 + var child = new NavigationContext();
  171 + parent.appendChild(child);
  172 +
  173 + var val;
  174 + parent.addListener('yo', event => event.preventDefault(), true);
  175 + child.addListener('yo', event => val = event.defaultPrevented, true);
  176 +
  177 + child.emit('yo');
  178 +
  179 + expect(val).toBe(true);
  180 + });
  181 +
  182 + it('prevents event at bubble phase', () => {
  183 + var parent = new NavigationContext();
  184 + var child = new NavigationContext();
  185 + parent.appendChild(child);
  186 +
  187 + var val;
  188 + parent.addListener('yo', event => val = event.defaultPrevented);
  189 + child.addListener('yo', event => event.preventDefault());
  190 +
  191 + child.emit('yo');
  192 +
  193 + expect(val).toBe(true);
  194 + });
  195 +
  196 + it('emits nested events in order at capture phase', () => {
  197 + var parent = new NavigationContext();
  198 + var child = new NavigationContext();
  199 + parent.appendChild(child);
  200 +
  201 + var logs = [];
  202 +
  203 + var listener = (event) => {
  204 + var {currentTarget, type} = event;
  205 + logs.push({
  206 + currentTarget,
  207 + type,
  208 + });
  209 + };
  210 +
  211 + child.addListener('yo', event => {
  212 + // event `didyo` should be fired after the full propagation cycle of the
  213 + // `yo` event.
  214 + child.emit('didyo');
  215 + });
  216 +
  217 + parent.addListener('yo', listener, true);
  218 + parent.addListener('didyo', listener, true);
  219 + child.addListener('yo', listener, true);
  220 +
  221 + child.emit('yo');
  222 +
  223 + expect(logs).toEqual([
  224 + {type: 'yo', currentTarget: parent},
  225 + {type: 'yo', currentTarget: child},
  226 + {type: 'didyo', currentTarget: parent},
  227 + ]);
  228 + });
  229 +
  230 + it('emits nested events in order at bubbling phase', () => {
  231 + var parent = new NavigationContext();
  232 + var child = new NavigationContext();
  233 + parent.appendChild(child);
  234 +
  235 + var logs = [];
  236 +
  237 + var listener = (event) => {
  238 + var {currentTarget, type} = event;
  239 + logs.push({
  240 + currentTarget,
  241 + type,
  242 + });
  243 + };
  244 +
  245 + child.addListener('yo', event => {
  246 + // event `didyo` should be fired after the full propagation cycle of the
  247 + // `yo` event.
  248 + child.emit('didyo');
  249 + });
  250 +
  251 + parent.addListener('yo', listener);
  252 + child.addListener('yo', listener);
  253 + parent.addListener('didyo', listener);
  254 +
  255 + child.emit('yo');
  256 +
  257 + expect(logs).toEqual([
  258 + {type: 'yo', currentTarget: child},
  259 + {type: 'yo', currentTarget: parent},
  260 + {type: 'didyo', currentTarget: parent},
  261 + ]);
  262 + });
  263 +});
  1 +/**
  2 + * Copyright (c) 2015, Facebook, Inc. All rights reserved.
  3 + *
  4 + * Facebook, Inc. ("Facebook") owns all right, title and interest, including
  5 + * all intellectual property and other proprietary rights, in and to the React
  6 + * Native CustomComponents software (the "Software"). Subject to your
  7 + * compliance with these terms, you are hereby granted a non-exclusive,
  8 + * worldwide, royalty-free copyright license to (1) use and copy the Software;
  9 + * and (2) reproduce and distribute the Software as part of your own software
  10 + * ("Your Software"). Facebook reserves all rights not expressly granted to
  11 + * you in this license agreement.
  12 + *
  13 + * THE SOFTWARE AND DOCUMENTATION, IF ANY, ARE PROVIDED "AS IS" AND ANY EXPRESS
  14 + * OR IMPLIED WARRANTIES (INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  15 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE) ARE DISCLAIMED.
  16 + * IN NO EVENT SHALL FACEBOOK OR ITS AFFILIATES, OFFICERS, DIRECTORS OR
  17 + * EMPLOYEES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  18 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  19 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  20 + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  21 + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  22 + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE SOFTWARE, EVEN IF
  23 + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  24 + */
  25 +'use strict';
  26 +
  27 +jest
  28 + .unmock('NavigationEvent')
  29 + .unmock('fbjs/lib/invariant');
  30 +
  31 +var NavigationEvent = require('NavigationEvent');
  32 +
  33 +describe('NavigationEvent', () => {
  34 + it('constructs', () => {
  35 + var target = {};
  36 + var event = new NavigationEvent('foo', target, 123);
  37 + expect(event.type).toBe('foo');
  38 + expect(event.target).toBe(target);
  39 + expect(event.data).toBe(123);
  40 + });
  41 +
  42 + it('constructs from pool', () => {
  43 + var target = {};
  44 + var event = NavigationEvent.pool('foo', target, 123);
  45 + expect(event.type).toBe('foo');
  46 + expect(event.target).toBe(target);
  47 + expect(event.data).toBe(123);
  48 + });
  49 +
  50 + it('prevents default', () => {
  51 + var event = new NavigationEvent('foo', {}, 123);
  52 + expect(event.defaultPrevented).toBe(false);
  53 + event.preventDefault();
  54 + expect(event.defaultPrevented).toBe(true);
  55 + });
  56 +
  57 + it('recycles', () => {
  58 + var event1 = NavigationEvent.pool('foo', {}, 123);
  59 + event1.dispose();
  60 + expect(event1.type).toBeFalsy();
  61 + expect(event1.data).toBe(null);
  62 + expect(event1.target).toBe(null);
  63 +
  64 + var event2 = NavigationEvent.pool('bar', {}, 456);
  65 + expect(event2.type).toBe('bar');
  66 + expect(event2).toBe(event1);
  67 + });
  68 +});
  1 +/**
  2 + * Copyright (c) 2015, Facebook, Inc. All rights reserved.
  3 + *
  4 + * Facebook, Inc. ("Facebook") owns all right, title and interest, including
  5 + * all intellectual property and other proprietary rights, in and to the React
  6 + * Native CustomComponents software (the "Software"). Subject to your
  7 + * compliance with these terms, you are hereby granted a non-exclusive,
  8 + * worldwide, royalty-free copyright license to (1) use and copy the Software;
  9 + * and (2) reproduce and distribute the Software as part of your own software
  10 + * ("Your Software"). Facebook reserves all rights not expressly granted to
  11 + * you in this license agreement.
  12 + *
  13 + * THE SOFTWARE AND DOCUMENTATION, IF ANY, ARE PROVIDED "AS IS" AND ANY EXPRESS
  14 + * OR IMPLIED WARRANTIES (INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  15 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE) ARE DISCLAIMED.
  16 + * IN NO EVENT SHALL FACEBOOK OR ITS AFFILIATES, OFFICERS, DIRECTORS OR
  17 + * EMPLOYEES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  18 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  19 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  20 + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  21 + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  22 + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE SOFTWARE, EVEN IF
  23 + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  24 + */
  25 +'use strict';
  26 +
  27 +jest
  28 + .unmock('EmitterSubscription')
  29 + .unmock('EventSubscription')
  30 + .unmock('EventEmitter')
  31 + .unmock('EventSubscriptionVendor')
  32 + .unmock('NavigationEvent')
  33 + .unmock('NavigationEventEmitter');
  34 +
  35 +var NavigationEventEmitter = require('NavigationEventEmitter');
  36 +
  37 +describe('NavigationEventEmitter', () => {
  38 + it('emits event', () => {
  39 + var context = {};
  40 + var emitter = new NavigationEventEmitter(context);
  41 + var logs = [];
  42 +
  43 + emitter.addListener('ping', (event) => {
  44 + var {type, data, target, defaultPrevented} = event;
  45 +
  46 + logs.push({
  47 + data,
  48 + defaultPrevented,
  49 + target,
  50 + type,
  51 + });
  52 +
  53 + });
  54 +
  55 + emitter.emit('ping', 'hello');
  56 +
  57 + expect(logs.length).toBe(1);
  58 + expect(logs[0].target).toBe(context);
  59 + expect(logs[0].type).toBe('ping');
  60 + expect(logs[0].data).toBe('hello');
  61 + expect(logs[0].defaultPrevented).toBe(false);
  62 + });
  63 +
  64 + it('does not emit event that has no listeners', () => {
  65 + var context = {};
  66 + var emitter = new NavigationEventEmitter(context);
  67 + var pinged = false;
  68 +
  69 + emitter.addListener('ping', () => {
  70 + pinged = true;
  71 + });
  72 +
  73 + emitter.emit('yo', 'bo');
  74 + expect(pinged).toBe(false);
  75 + });
  76 +
  77 + it('puts nested emit call in a queue', () => {
  78 + var context = {};
  79 + var emitter = new NavigationEventEmitter(context);
  80 + var logs = [];
  81 +
  82 + emitter.addListener('one', () => {
  83 + logs.push(1);
  84 + emitter.emit('two');
  85 + logs.push(2);
  86 + });
  87 +
  88 + emitter.addListener('two', () => {
  89 + logs.push(3);
  90 + emitter.emit('three');
  91 + logs.push(4);
  92 + });
  93 +
  94 + emitter.addListener('three', () => {
  95 + logs.push(5);
  96 + });
  97 +
  98 + emitter.emit('one');
  99 +
  100 + expect(logs).toEqual([1, 2, 3, 4, 5]);
  101 + });
  102 +
  103 + it('puts nested emit call in a queue should be in sequence order', () => {
  104 + var context = {};
  105 + var emitter = new NavigationEventEmitter(context);
  106 + var logs = [];
  107 +
  108 + emitter.addListener('one', () => {
  109 + logs.push(1);
  110 + emitter.emit('two');
  111 + emitter.emit('three');
  112 + logs.push(2);
  113 + });
  114 +
  115 + emitter.addListener('two', () => {
  116 + logs.push(3);
  117 + logs.push(4);
  118 + });
  119 +
  120 + emitter.addListener('three', () => {
  121 + logs.push(5);
  122 + });
  123 +
  124 + emitter.emit('one');
  125 +
  126 + expect(logs).toEqual([1, 2, 3, 4, 5]);
  127 + });
  128 +
  129 + it('calls callback after emitting', () => {
  130 + var context = {};
  131 + var emitter = new NavigationEventEmitter(context);
  132 + var logs = [];
  133 +
  134 + emitter.addListener('ping', (event) => {
  135 + var {type, data, target, defaultPrevented} = event;
  136 + logs.push({
  137 + data,
  138 + defaultPrevented,
  139 + target,
  140 + type,
  141 + });
  142 + event.preventDefault();
  143 + });
  144 +
  145 + emitter.emit('ping', 'hello', (event) => {
  146 + var {type, data, target, defaultPrevented} = event;
  147 + logs.push({
  148 + data,
  149 + defaultPrevented,
  150 + target,
  151 + type,
  152 + });
  153 + });
  154 +
  155 + expect(logs.length).toBe(2);
  156 + expect(logs[1].target).toBe(context);
  157 + expect(logs[1].type).toBe('ping');
  158 + expect(logs[1].data).toBe('hello');
  159 + expect(logs[1].defaultPrevented).toBe(true);
  160 + });
  161 +
  162 + it('calls callback after emitting the current event and before ' +
  163 + 'emitting the next event', () => {
  164 + var context = {};
  165 + var emitter = new NavigationEventEmitter(context);
  166 + var logs = [];
  167 +
  168 + emitter.addListener('ping', (event) => {
  169 + logs.push('ping');
  170 + emitter.emit('pong');
  171 + });
  172 +
  173 + emitter.addListener('pong', (event) => {
  174 + logs.push('pong');
  175 + });
  176 +
  177 + emitter.emit('ping', null, () => {
  178 + logs.push('did-ping');
  179 + });
  180 +
  181 + expect(logs).toEqual([
  182 + 'ping',
  183 + 'did-ping',
  184 + 'pong',
  185 + ]);
  186 + });
  187 +});
This diff is collapsed. Click to expand it.
  1 +/**
  2 + * Copyright (c) 2015, Facebook, Inc. All rights reserved.
  3 + */
  4 +
  5 +'use strict';
  6 +
  7 +jest
  8 + .unmock('NavigationTreeNode')
  9 + .unmock('fbjs/lib/invariant')
  10 + .unmock('immutable');
  11 +
  12 +var NavigationTreeNode = require('NavigationTreeNode');
  13 +
  14 +describe('NavigationTreeNode-test', () => {
  15 + it('should be empty', () => {
  16 + var node = new NavigationTreeNode();
  17 + expect(node.getValue()).toEqual(undefined);
  18 + expect(node.getParent()).toEqual(null);
  19 + expect(node.getChildrenCount()).toEqual(0);
  20 + expect(node.getChildAt(0)).toEqual(null);
  21 + });
  22 +
  23 +
  24 + it('should contain value', () => {
  25 + var node = new NavigationTreeNode(123);
  26 + expect(node.getValue()).toEqual(123);
  27 + });
  28 +
  29 + it('should appendChild', () => {
  30 + var papa = new NavigationTreeNode('hedger');
  31 + var baby = new NavigationTreeNode('hedger jr');
  32 + papa.appendChild(baby);
  33 + expect(papa.getChildAt(0)).toEqual(baby);
  34 + expect(papa.getChildrenCount()).toEqual(1);
  35 + expect(baby.getParent()).toEqual(papa);
  36 + });
  37 +
  38 + it('should removeChild', () => {
  39 + var papa = new NavigationTreeNode('Eddard Stark');
  40 + var baby = new NavigationTreeNode('Robb Stark');
  41 + papa.appendChild(baby);
  42 +
  43 + papa.removeChild(baby);
  44 + expect(papa.getChildAt(0)).toEqual(null);
  45 + expect(papa.getChildrenCount()).toEqual(0);
  46 + expect(baby.getParent()).toEqual(null);
  47 + });
  48 +
  49 + it('should not remove non-child', () => {
  50 + var papa = new NavigationTreeNode('dog');
  51 + var baby = new NavigationTreeNode('cat');
  52 + expect(papa.removeChild.bind(papa, baby)).toThrow();
  53 + });
  54 +
  55 + it('should find child', () => {
  56 + var papa = new NavigationTreeNode('Eddard Stark');
  57 + var baby = new NavigationTreeNode('Robb Stark');
  58 +
  59 + papa.appendChild(baby);
  60 + expect(papa.indexOf(baby)).toEqual(0);
  61 +
  62 + papa.removeChild(baby);
  63 + expect(papa.indexOf(baby)).toEqual(-1);
  64 + });
  65 +
  66 +
  67 + it('should traverse each child', () => {
  68 + var parent = new NavigationTreeNode();
  69 + parent.appendChild(new NavigationTreeNode('a'));
  70 + parent.appendChild(new NavigationTreeNode('b'));
  71 + parent.appendChild(new NavigationTreeNode('c'));
  72 + var result = [];
  73 + parent.forEach((child, index) => {
  74 + result[index] = child.getValue();
  75 + });
  76 +
  77 + expect(result).toEqual(['a', 'b', 'c']);
  78 + });
  79 +
  80 + it('should map children', () => {
  81 + var parent = new NavigationTreeNode();
  82 + parent.appendChild(new NavigationTreeNode('a'));
  83 + parent.appendChild(new NavigationTreeNode('b'));
  84 + parent.appendChild(new NavigationTreeNode('c'));
  85 + var result = parent.map((child, index) => {
  86 + return child.getValue();
  87 + });
  88 +
  89 + expect(result).toEqual(['a', 'b', 'c']);
  90 + });
  91 +
  92 + it('should traverse some children', () => {
  93 + var parent = new NavigationTreeNode();
  94 + parent.appendChild(new NavigationTreeNode('a'));
  95 + parent.appendChild(new NavigationTreeNode('b'));
  96 + parent.appendChild(new NavigationTreeNode('c'));
  97 +
  98 + var result = [];
  99 + var value = parent.some((child, index) => {
  100 + if (index > 1) {
  101 + return true;
  102 + } else {
  103 + result[index] = child.getValue();
  104 + }
  105 + });
  106 +
  107 + expect(value).toEqual(true);
  108 + expect(result).toEqual(['a', 'b']);
  109 + });
  110 +});
This diff is collapsed. Click to expand it.
  1 +/**
  2 + * Copyright (c) 2015, Facebook, Inc. All rights reserved.
  3 + *
  4 + * Facebook, Inc. ("Facebook") owns all right, title and interest, including
  5 + * all intellectual property and other proprietary rights, in and to the React
  6 + * Native CustomComponents software (the "Software"). Subject to your
  7 + * compliance with these terms, you are hereby granted a non-exclusive,
  8 + * worldwide, royalty-free copyright license to (1) use and copy the Software;
  9 + * and (2) reproduce and distribute the Software as part of your own software
  10 + * ("Your Software"). Facebook reserves all rights not expressly granted to
  11 + * you in this license agreement.
  12 + *
  13 + * THE SOFTWARE AND DOCUMENTATION, IF ANY, ARE PROVIDED "AS IS" AND ANY EXPRESS
  14 + * OR IMPLIED WARRANTIES (INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  15 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE) ARE DISCLAIMED.
  16 + * IN NO EVENT SHALL FACEBOOK OR ITS AFFILIATES, OFFICERS, DIRECTORS OR
  17 + * EMPLOYEES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  18 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  19 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  20 + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  21 + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  22 + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE SOFTWARE, EVEN IF
  23 + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  24 + *
  25 + * @typechecks
  26 + */
  27 +'use strict';
  28 +
  29 +/**
  30 + * @param {number} value
  31 + * @param {number} min
  32 + * @param {number} max
  33 + * @return {number}
  34 + */
  35 +function clamp(min, value, max) {
  36 + if (value < min) {
  37 + return min;
  38 + }
  39 + if (value > max) {
  40 + return max;
  41 + }
  42 + return value;
  43 +}
  44 +
  45 +module.exports = clamp;
  1 +/**
  2 + * Copyright (c) 2015, Facebook, Inc. All rights reserved.
  3 + *
  4 + * Facebook, Inc. ("Facebook") owns all right, title and interest, including
  5 + * all intellectual property and other proprietary rights, in and to the React
  6 + * Native CustomComponents software (the "Software"). Subject to your
  7 + * compliance with these terms, you are hereby granted a non-exclusive,
  8 + * worldwide, royalty-free copyright license to (1) use and copy the Software;
  9 + * and (2) reproduce and distribute the Software as part of your own software
  10 + * ("Your Software"). Facebook reserves all rights not expressly granted to
  11 + * you in this license agreement.
  12 + *
  13 + * THE SOFTWARE AND DOCUMENTATION, IF ANY, ARE PROVIDED "AS IS" AND ANY EXPRESS
  14 + * OR IMPLIED WARRANTIES (INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  15 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE) ARE DISCLAIMED.
  16 + * IN NO EVENT SHALL FACEBOOK OR ITS AFFILIATES, OFFICERS, DIRECTORS OR
  17 + * EMPLOYEES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  18 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  19 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  20 + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  21 + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  22 + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE SOFTWARE, EVEN IF
  23 + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  24 + *
  25 + * @flow
  26 + */
  27 +'use strict';
  28 +
  29 +var invariant = require('fbjs/lib/invariant');
  30 +
  31 +import type { StyleObj } from 'StyleSheetTypes';
  32 +
  33 +function getStyle(style) {
  34 + if (style && typeof style === 'number') {
  35 + debugger;
  36 + invariant(false, "Error when using Navigator from react-native-custom-components. Please provide a raw object to `props.sceneStyle` instead of a StyleSheet reference.");
  37 + }
  38 + return style;
  39 +}
  40 +
  41 +function flattenStyle(style: ?StyleObj): ?Object {
  42 + if (!style) {
  43 + return undefined;
  44 + }
  45 + invariant(style !== true, 'style may be false but not true');
  46 +
  47 + if (!Array.isArray(style)) {
  48 + return getStyle(style);
  49 + }
  50 +
  51 + var result = {};
  52 + for (var i = 0, styleLength = style.length; i < styleLength; ++i) {
  53 + var computedStyle = flattenStyle(style[i]);
  54 + if (computedStyle) {
  55 + for (var key in computedStyle) {
  56 + result[key] = computedStyle[key];
  57 + }
  58 + }
  59 + }
  60 + return result;
  61 +}
  62 +
  63 +module.exports = flattenStyle;
  1 +/**
  2 + * Copyright (c) 2015, Facebook, Inc. All rights reserved.
  3 + *
  4 + * Facebook, Inc. ("Facebook") owns all right, title and interest, including
  5 + * all intellectual property and other proprietary rights, in and to the React
  6 + * Native CustomComponents software (the "Software"). Subject to your
  7 + * compliance with these terms, you are hereby granted a non-exclusive,
  8 + * worldwide, royalty-free copyright license to (1) use and copy the Software;
  9 + * and (2) reproduce and distribute the Software as part of your own software
  10 + * ("Your Software"). Facebook reserves all rights not expressly granted to
  11 + * you in this license agreement.
  12 + *
  13 + * THE SOFTWARE AND DOCUMENTATION, IF ANY, ARE PROVIDED "AS IS" AND ANY EXPRESS
  14 + * OR IMPLIED WARRANTIES (INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  15 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE) ARE DISCLAIMED.
  16 + * IN NO EVENT SHALL FACEBOOK OR ITS AFFILIATES, OFFICERS, DIRECTORS OR
  17 + * EMPLOYEES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  18 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  19 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  20 + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  21 + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  22 + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE SOFTWARE, EVEN IF
  23 + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  24 + *
  25 + */
  26 +
  27 +/* eslint-disable no-bitwise */
  28 +
  29 +'use strict';
  30 +
  31 +/**
  32 + * Module that provides a function for creating a unique identifier.
  33 + * The returned value does not conform to the GUID standard, but should
  34 + * be globally unique in the context of the browser.
  35 + */
  36 +function guid() {
  37 + return 'f' + (Math.random() * (1 << 30)).toString(16).replace('.', '');
  38 +}
  39 +
  40 +module.exports = guid;
  1 +/**
  2 + * Copyright (c) 2015, Facebook, Inc. All rights reserved.
  3 + *
  4 + * Facebook, Inc. ("Facebook") owns all right, title and interest, including
  5 + * all intellectual property and other proprietary rights, in and to the React
  6 + * Native CustomComponents software (the "Software"). Subject to your
  7 + * compliance with these terms, you are hereby granted a non-exclusive,
  8 + * worldwide, royalty-free copyright license to (1) use and copy the Software;
  9 + * and (2) reproduce and distribute the Software as part of your own software
  10 + * ("Your Software"). Facebook reserves all rights not expressly granted to
  11 + * you in this license agreement.
  12 + *
  13 + * THE SOFTWARE AND DOCUMENTATION, IF ANY, ARE PROVIDED "AS IS" AND ANY EXPRESS
  14 + * OR IMPLIED WARRANTIES (INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  15 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE) ARE DISCLAIMED.
  16 + * IN NO EVENT SHALL FACEBOOK OR ITS AFFILIATES, OFFICERS, DIRECTORS OR
  17 + * EMPLOYEES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  18 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  19 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  20 + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  21 + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  22 + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE SOFTWARE, EVEN IF
  23 + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  24 + *
  25 + */
  26 +
  27 +"use strict";
  28 +
  29 +var mergeInto = require('./mergeInto');
  30 +
  31 +/**
  32 + * Shallow merges two structures into a return value, without mutating either.
  33 + *
  34 + * @param {?object} one Optional object with properties to merge from.
  35 + * @param {?object} two Optional object with properties to merge from.
  36 + * @return {object} The shallow extension of one by two.
  37 + */
  38 +var merge = function(one, two) {
  39 + var result = {};
  40 + mergeInto(result, one);
  41 + mergeInto(result, two);
  42 + return result;
  43 +};
  44 +
  45 +module.exports = merge;
  1 +/**
  2 + * Copyright (c) 2015, Facebook, Inc. All rights reserved.
  3 + *
  4 + * Facebook, Inc. ("Facebook") owns all right, title and interest, including
  5 + * all intellectual property and other proprietary rights, in and to the React
  6 + * Native CustomComponents software (the "Software"). Subject to your
  7 + * compliance with these terms, you are hereby granted a non-exclusive,
  8 + * worldwide, royalty-free copyright license to (1) use and copy the Software;
  9 + * and (2) reproduce and distribute the Software as part of your own software
  10 + * ("Your Software"). Facebook reserves all rights not expressly granted to
  11 + * you in this license agreement.
  12 + *
  13 + * THE SOFTWARE AND DOCUMENTATION, IF ANY, ARE PROVIDED "AS IS" AND ANY EXPRESS
  14 + * OR IMPLIED WARRANTIES (INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  15 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE) ARE DISCLAIMED.
  16 + * IN NO EVENT SHALL FACEBOOK OR ITS AFFILIATES, OFFICERS, DIRECTORS OR
  17 + * EMPLOYEES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  18 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  19 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  20 + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  21 + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  22 + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE SOFTWARE, EVEN IF
  23 + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  24 + *
  25 + * requiresPolyfills: Array.isArray
  26 + */
  27 +
  28 +"use strict";
  29 +
  30 +var invariant = require('fbjs/lib/invariant');
  31 +var keyMirror = require('fbjs/lib/keyMirror');
  32 +
  33 +/**
  34 + * Maximum number of levels to traverse. Will catch circular structures.
  35 + * @const
  36 + */
  37 +var MAX_MERGE_DEPTH = 36;
  38 +
  39 +/**
  40 + * We won't worry about edge cases like new String('x') or new Boolean(true).
  41 + * Functions are considered terminals, and arrays are not.
  42 + * @param {*} o The item/object/value to test.
  43 + * @return {boolean} true iff the argument is a terminal.
  44 + */
  45 +var isTerminal = function(o) {
  46 + return typeof o !== 'object' || o === null;
  47 +};
  48 +
  49 +var mergeHelpers = {
  50 +
  51 + MAX_MERGE_DEPTH: MAX_MERGE_DEPTH,
  52 +
  53 + isTerminal: isTerminal,
  54 +
  55 + /**
  56 + * Converts null/undefined values into empty object.
  57 + *
  58 + * @param {?Object=} arg Argument to be normalized (nullable optional)
  59 + * @return {!Object}
  60 + */
  61 + normalizeMergeArg: function(arg) {
  62 + return arg === undefined || arg === null ? {} : arg;
  63 + },
  64 +
  65 + /**
  66 + * If merging Arrays, a merge strategy *must* be supplied. If not, it is
  67 + * likely the caller's fault. If this function is ever called with anything
  68 + * but `one` and `two` being `Array`s, it is the fault of the merge utilities.
  69 + *
  70 + * @param {*} one Array to merge into.
  71 + * @param {*} two Array to merge from.
  72 + */
  73 + checkMergeArrayArgs: function(one, two) {
  74 + invariant(
  75 + Array.isArray(one) && Array.isArray(two),
  76 + 'Tried to merge arrays, instead got %s and %s.',
  77 + one,
  78 + two
  79 + );
  80 + },
  81 +
  82 + /**
  83 + * @param {*} one Object to merge into.
  84 + * @param {*} two Object to merge from.
  85 + */
  86 + checkMergeObjectArgs: function(one, two) {
  87 + mergeHelpers.checkMergeObjectArg(one);
  88 + mergeHelpers.checkMergeObjectArg(two);
  89 + },
  90 +
  91 + /**
  92 + * @param {*} arg
  93 + */
  94 + checkMergeObjectArg: function(arg) {
  95 + invariant(
  96 + !isTerminal(arg) && !Array.isArray(arg),
  97 + 'Tried to merge an object, instead got %s.',
  98 + arg
  99 + );
  100 + },
  101 +
  102 + /**
  103 + * @param {*} arg
  104 + */
  105 + checkMergeIntoObjectArg: function(arg) {
  106 + invariant(
  107 + (!isTerminal(arg) || typeof arg === 'function') && !Array.isArray(arg),
  108 + 'Tried to merge into an object, instead got %s.',
  109 + arg
  110 + );
  111 + },
  112 +
  113 + /**
  114 + * Checks that a merge was not given a circular object or an object that had
  115 + * too great of depth.
  116 + *
  117 + * @param {number} Level of recursion to validate against maximum.
  118 + */
  119 + checkMergeLevel: function(level) {
  120 + invariant(
  121 + level < MAX_MERGE_DEPTH,
  122 + 'Maximum deep merge depth exceeded. You may be attempting to merge ' +
  123 + 'circular structures in an unsupported way.'
  124 + );
  125 + },
  126 +
  127 + /**
  128 + * Checks that the supplied merge strategy is valid.
  129 + *
  130 + * @param {string} Array merge strategy.
  131 + */
  132 + checkArrayStrategy: function(strategy) {
  133 + invariant(
  134 + strategy === undefined || strategy in mergeHelpers.ArrayStrategies,
  135 + 'You must provide an array strategy to deep merge functions to ' +
  136 + 'instruct the deep merge how to resolve merging two arrays.'
  137 + );
  138 + },
  139 +
  140 + /**
  141 + * Set of possible behaviors of merge algorithms when encountering two Arrays
  142 + * that must be merged together.
  143 + * - `clobber`: The left `Array` is ignored.
  144 + * - `indexByIndex`: The result is achieved by recursively deep merging at
  145 + * each index. (not yet supported.)
  146 + */
  147 + ArrayStrategies: keyMirror({
  148 + Clobber: true,
  149 + IndexByIndex: true
  150 + })
  151 +
  152 +};
  153 +
  154 +module.exports = mergeHelpers;
  1 +/**
  2 + * Copyright (c) 2015, Facebook, Inc. All rights reserved.
  3 + *
  4 + * Facebook, Inc. ("Facebook") owns all right, title and interest, including
  5 + * all intellectual property and other proprietary rights, in and to the React
  6 + * Native CustomComponents software (the "Software"). Subject to your
  7 + * compliance with these terms, you are hereby granted a non-exclusive,
  8 + * worldwide, royalty-free copyright license to (1) use and copy the Software;
  9 + * and (2) reproduce and distribute the Software as part of your own software
  10 + * ("Your Software"). Facebook reserves all rights not expressly granted to
  11 + * you in this license agreement.
  12 + *
  13 + * THE SOFTWARE AND DOCUMENTATION, IF ANY, ARE PROVIDED "AS IS" AND ANY EXPRESS
  14 + * OR IMPLIED WARRANTIES (INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  15 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE) ARE DISCLAIMED.
  16 + * IN NO EVENT SHALL FACEBOOK OR ITS AFFILIATES, OFFICERS, DIRECTORS OR
  17 + * EMPLOYEES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  18 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  19 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  20 + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  21 + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  22 + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE SOFTWARE, EVEN IF
  23 + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  24 + *
  25 + * @typechecks static-only
  26 + */
  27 +
  28 +"use strict";
  29 +
  30 +var mergeHelpers = require('./mergeHelpers');
  31 +
  32 +var checkMergeObjectArg = mergeHelpers.checkMergeObjectArg;
  33 +var checkMergeIntoObjectArg = mergeHelpers.checkMergeIntoObjectArg;
  34 +
  35 +/**
  36 + * Shallow merges two structures by mutating the first parameter.
  37 + *
  38 + * @param {object|function} one Object to be merged into.
  39 + * @param {?object} two Optional object with properties to merge from.
  40 + */
  41 +function mergeInto(one, two) {
  42 + checkMergeIntoObjectArg(one);
  43 + if (two != null) {
  44 + checkMergeObjectArg(two);
  45 + for (var key in two) {
  46 + if (!two.hasOwnProperty(key)) {
  47 + continue;
  48 + }
  49 + one[key] = two[key];
  50 + }
  51 + }
  52 +}
  53 +
  54 +module.exports = mergeInto;