Updates from Wed 20 May

This commit is contained in:
Alexsander Akers 2015-05-20 18:04:26 +01:00
commit 4cd5cad599
53 changed files with 294 additions and 64 deletions

View File

@ -1,3 +1,5 @@
**/node_modules/**/.*js
# node_modules ignored by default
**/staticBundle.js
**/main.js
Libraries/vendor/**/*

View File

@ -168,7 +168,7 @@
"no-underscore-dangle": 0, // disallow dangling underscores in identifiers
"no-wrap-func": 1, // disallow wrapping of non-IIFE statements in parens
"no-mixed-spaces-and-tabs": 1, // disallow mixed spaces and tabs for indentation
"quotes": [1, "single"], // specify whether double or single quotes should be used
"quotes": [1, "single", "avoid-escape"], // specify whether double or single quotes should be used
"quote-props": 0, // require quotes around object literal property names (off by default)
"semi": 1, // require or disallow use of semicolons instead of ASI
"sort-vars": 0, // sort variables within the same declaration block (off by default)

View File

@ -0,0 +1,62 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @providesModule AppEventsTest
* @flow
*/
'use strict';
var React = require('react-native');
var {
NativeAppEventEmitter,
NativeModules,
StyleSheet,
Text,
View,
} = React;
var TestModule = NativeModules.TestModule || NativeModules.SnapshotTestManager;
var deepDiffer = require('deepDiffer');
var TEST_PAYLOAD = {foo: 'bar'};
var AppEventsTest = React.createClass({
getInitialState: function() {
return {sent: 'none', received: 'none'};
},
componentDidMount: function() {
NativeAppEventEmitter.addListener('testEvent', this.receiveEvent);
var event = {data: TEST_PAYLOAD, ts: Date.now()};
TestModule.sendAppEvent('testEvent', event);
this.setState({sent: event});
},
receiveEvent: function(event: any) {
if (deepDiffer(event.data, TEST_PAYLOAD)) {
throw new Error('Received wrong event: ' + JSON.stringify(event));
}
var elapsed = (Date.now() - event.ts) + 'ms';
this.setState({received: event, elapsed}, TestModule.markTestCompleted);
},
render: function() {
return (
<View style={styles.container}>
<Text>
{JSON.stringify(this.state, null, ' ')}
</Text>
</View>
);
}
});
var styles = StyleSheet.create({
container: {
margin: 40,
},
});
module.exports = AppEventsTest;

View File

@ -26,6 +26,7 @@ var TESTS = [
require('./TimersTest'),
require('./AsyncStorageTest'),
require('./LayoutEventsTest'),
require('./AppEventsTest'),
require('./SimpleSnapshotTest'),
];

View File

@ -76,6 +76,11 @@
[_runner runTest:_cmd module:@"LayoutEventsTest"];
}
- (void)testAppEvents
{
[_runner runTest:_cmd module:@"AppEventsTest"];
}
#pragma mark Snapshot Tests
- (void)testSimpleSnapshot

View File

@ -8,8 +8,7 @@
*
* @providesModule ARTSerializablePath
*/
"use strict";
'use strict';
// TODO: Move this into an ART mode called "serialized" or something

View File

@ -8,8 +8,7 @@
*
* @providesModule ReactNativeART
*/
"use strict";
'use strict';
var Color = require('art/core/color');
var Path = require('ARTSerializablePath');

View File

@ -12,7 +12,6 @@
'use strict';
var NativeMethodsMixin = require('NativeMethodsMixin');
var NativeModules = require('NativeModules');
var PropTypes = require('ReactPropTypes');
var React = require('React');
var StyleSheet = require('StyleSheet');

View File

@ -183,7 +183,7 @@ var ScrollResponderMixin = {
var currentlyFocusedTextInput = TextInputState.currentlyFocusedField();
if (!this.props.keyboardShouldPersistTaps &&
currentlyFocusedTextInput != null &&
e.target != currentlyFocusedTextInput) {
e.target !== currentlyFocusedTextInput) {
return true;
}
return this.scrollResponderIsAnimating();
@ -244,7 +244,7 @@ var ScrollResponderMixin = {
var currentlyFocusedTextInput = TextInputState.currentlyFocusedField();
if (!this.props.keyboardShouldPersistTaps &&
currentlyFocusedTextInput != null &&
e.target != currentlyFocusedTextInput &&
e.target !== currentlyFocusedTextInput &&
!this.state.observedScrollSinceBecomingResponder &&
!this.state.becameResponderWhileAnimating) {
this.props.onScrollResponderKeyboardDismissed &&

View File

@ -11,7 +11,7 @@
*/
'use strict';
var EventEmitter = require('EventEmitter');
import type EventEmitter from 'EventEmitter';
/**
* Subscribable provides a mixin for safely subscribing a component to an

View File

@ -179,12 +179,12 @@ var TextInput = React.createClass({
'number-pad',
'phone-pad',
'name-phone-pad',
'email-address',
'decimal-pad',
'twitter',
'web-search',
// Cross-platform
'numeric',
'email-address',
]),
/**
* Determines how the return key should look.

View File

@ -24,6 +24,26 @@ var createReactNativeComponentClass = require('createReactNativeComponentClass')
var stylePropType = StyleSheetPropType(ViewStylePropTypes);
var AccessibilityTraits = [
'none',
'button',
'link',
'header',
'search',
'image',
'selected',
'plays',
'key',
'text',
'summary',
'disabled',
'frequentUpdates',
'startsMedia',
'adjustable',
'allowsDirectInteraction',
'pageTurn',
];
/**
* The most fundamental component for building UI, `View` is a
* container that supports layout with flexbox, style, some touch handling, and
@ -70,6 +90,27 @@ var View = React.createClass({
*/
accessibilityLabel: PropTypes.string,
/**
* Provides additional traits to screen reader. By default no traits are
* provided unless specified otherwise in element
*/
accessibilityTraits: PropTypes.oneOfType([
PropTypes.oneOf(AccessibilityTraits),
PropTypes.arrayOf(PropTypes.oneOf(AccessibilityTraits)),
]),
/**
* When `accessible` is true, the system will try to invoke this function
* when the user performs accessibility tap gesture.
*/
onAcccessibilityTap: PropTypes.func,
/**
* When `accessible` is true, the system will invoke this function when the
* user performs the magic tap gesture.
*/
onMagicTap: PropTypes.func,
/**
* Used to locate this view in end-to-end tests.
*/

View File

@ -75,7 +75,7 @@ var WebView = React.createClass({
errorEvent.code,
errorEvent.description);
} else if (this.state.viewState !== WebViewState.IDLE) {
console.error("RCTWebView invalid state encountered: " + this.state.loading);
console.error('RCTWebView invalid state encountered: ' + this.state.loading);
}
var webViewStyles = [styles.container, this.props.style];
@ -152,7 +152,7 @@ var WebView = React.createClass({
onLoadingError: function(event) {
event.persist(); // persist this event because we need to store it
console.error("encountered an error loading page", event.nativeEvent);
console.error('Encountered an error loading page', event.nativeEvent);
this.setState({
lastErrorEvent: event.nativeEvent,

View File

@ -14,7 +14,6 @@
var ActivityIndicatorIOS = require('ActivityIndicatorIOS');
var EdgeInsetsPropType = require('EdgeInsetsPropType');
var React = require('React');
var ReactNativeViewAttributes = require('ReactNativeViewAttributes');
var StyleSheet = require('StyleSheet');
var Text = require('Text');
var View = require('View');
@ -198,7 +197,7 @@ var WebView = React.createClass({
onLoadingError: function(event: Event) {
event.persist(); // persist this event because we need to store it
console.error("encountered an error loading page", event.nativeEvent);
console.error('Encountered an error loading page', event.nativeEvent);
this.setState({
lastErrorEvent: event.nativeEvent,

View File

@ -24,6 +24,7 @@
*
* @providesModule Navigator
*/
/* eslint-disable no-extra-boolean-cast*/
'use strict';
var AnimationsDebugModule = require('NativeModules').AnimationsDebugModule;
@ -48,8 +49,6 @@ var clamp = require('clamp');
var flattenStyle = require('flattenStyle');
var getNavigatorContext = require('getNavigatorContext');
var invariant = require('invariant');
var keyMirror = require('keyMirror');
var merge = require('merge');
var rebound = require('rebound');
var PropTypes = React.PropTypes;
@ -689,7 +688,7 @@ var Navigator = React.createClass({
*/
_enableScene: function(sceneIndex) {
// First, determine what the defined styles are for scenes in this navigator
var sceneStyle = flattenStyle(this.props.sceneStyle);
var sceneStyle = flattenStyle([styles.baseScene, this.props.sceneStyle]);
// Then restore the left value for this scene
var enabledSceneNativeProps = {
left: sceneStyle.left,
@ -745,7 +744,6 @@ var Navigator = React.createClass({
},
_handleMoveShouldSetPanResponder: function(e, gestureState) {
var currentRoute = this.state.routeStack[this.state.presentedIndex];
var sceneConfig = this.state.sceneConfigStack[this.state.presentedIndex];
this._expectingGestureGrant = this._matchGestureAction(this._eligibleGestures, sceneConfig.gestures, gestureState);
return !! this._expectingGestureGrant;
@ -829,7 +827,16 @@ var Navigator = React.createClass({
}
} else {
// The gesture has enough velocity to complete, so we transition to the gesture's destination
this._transitionTo(destIndex, transitionVelocity);
this._transitionTo(
destIndex,
transitionVelocity,
null,
() => {
if (releaseGestureAction === 'pop') {
this._cleanScenesPastIndex(destIndex);
}
}
);
}
this._detachGesture();
},

View File

@ -213,7 +213,7 @@ var FromTheLeft = {
translateX: {
from: -SCREEN_WIDTH,
to: 0,
min: 0,
min: 0,
max: 1,
type: 'linear',
extrapolate: true,

View File

@ -12,6 +12,7 @@
* @providesModule fetch
* @nolint
*/
/* eslint-disable */
'use strict';
var self = {};

View File

@ -120,6 +120,6 @@ var Geolocation = {
subscriptions = [];
}
}
}
};
module.exports = Geolocation;

View File

@ -60,7 +60,7 @@ var Image = React.createClass({
/**
* `uri` is a string representing the resource identifier for the image, which
* could be an http address, a local file path, or the name of a static image
* resource (which should be wrapped in the `required('image!name')` function).
* resource (which should be wrapped in the `require('image!name')` function).
*/
source: PropTypes.shape({
uri: PropTypes.string,

View File

@ -18,6 +18,7 @@
* and wrapping resulting file into `wrapper` function.
*
*/
/*eslint-disable */
var scope = {};
wrapper.call(scope);

View File

@ -11,6 +11,7 @@
*
* @nolint
*/
/* eslint-disable */
(function() {
var define = null; // Hack to make it work with our packager

View File

@ -11,7 +11,6 @@
*/
'use strict';
var NativeModules = require('NativeModules');
var RCTDeviceEventEmitter = require('RCTDeviceEventEmitter');
var RCTPushNotificationManager = require('NativeModules').PushNotificationManager;
var invariant = require('invariant');

View File

@ -11,6 +11,7 @@
#import "FBSnapshotTestController.h"
#import "RCTAssert.h"
#import "RCTEventDispatcher.h"
#import "RCTLog.h"
#import "RCTUIManager.h"
@ -63,4 +64,9 @@ RCT_EXPORT_METHOD(markTestCompleted)
}];
}
RCT_EXPORT_METHOD(sendAppEvent:(NSString *)name body:(id)body)
{
[_bridge.eventDispatcher sendAppEventWithName:name body:body];
}
@end

View File

@ -58,4 +58,3 @@ var queryLayoutByID = function(
};
module.exports = queryLayoutByID;

View File

@ -9,8 +9,7 @@
* @providesModule IOSNativeBridgeEventPlugin
* @flow
*/
"use strict";
'use strict';
var EventPropagators = require('EventPropagators');
var NativeModules = require('NativeModules');
@ -33,7 +32,7 @@ for (var bubblingTypeName in customBubblingEventTypes) {
for (var directTypeName in customDirectEventTypes) {
warning(
!customBubblingEventTypes[directTypeName],
"Event cannot be both direct and bubbling: %s",
'Event cannot be both direct and bubbling: %s',
directTypeName
);
allTypesByEventName[directTypeName] = customDirectEventTypes[directTypeName];
@ -76,4 +75,3 @@ var IOSNativeBridgeEventPlugin = {
};
module.exports = IOSNativeBridgeEventPlugin;

View File

@ -22,6 +22,13 @@ function verifyPropTypes(
if (!viewConfig) {
return; // This happens for UnimplementedView.
}
var componentName = component.name || component.displayName;
if (!component.propTypes) {
throw new Error(
'`' + componentName + '` has no propTypes defined`'
);
}
var nativeProps = viewConfig.nativeProps;
for (var prop in nativeProps) {
if (!component.propTypes[prop] &&
@ -29,9 +36,9 @@ function verifyPropTypes(
!ReactNativeStyleAttributes[prop] &&
(!nativePropsToIgnore || !nativePropsToIgnore[prop])) {
throw new Error(
'`' + component.displayName + '` has no propType for native prop `' +
'`' + componentName + '` has no propType for native prop `' +
viewConfig.uiViewClassName + '.' + prop + '` of native type `' +
nativeProps[prop].type + '`'
nativeProps[prop] + '`'
);
}
}

View File

@ -9,7 +9,6 @@
* @providesModule React
* @flow
*/
"use strict";
'use strict';
module.exports = require('ReactNative');

View File

@ -9,7 +9,7 @@
* @providesModule ReactNative
* @flow
*/
"use strict";
'use strict';
var ReactChildren = require('ReactChildren');
var ReactClass = require('ReactClass');

View File

@ -63,7 +63,8 @@ var cachedIndexArray = function(size) {
for (var i = 0; i < size; i++) {
arr[i] = i;
}
return cachedIndexArray._cache[size] = arr;
cachedIndexArray._cache[size] = arr;
return arr;
} else {
return cachedResult;
}
@ -228,7 +229,7 @@ ReactNativeBaseComponent.Mixin = {
*/
_reconcileListenersUponUpdate: function(prevProps, nextProps) {
for (var key in nextProps) {
if (registrationNames[key] && (nextProps[key] != prevProps[key])) {
if (registrationNames[key] && (nextProps[key] !== prevProps[key])) {
putListener(this._rootNodeID, key, nextProps[key]);
}
}

View File

@ -9,8 +9,7 @@
* @providesModule ReactNativeDOMIDOperations
* @flow
*/
"use strict";
'use strict';
var ReactNativeTagHandles = require('ReactNativeTagHandles');
var ReactMultiChildUpdateTypes = require('ReactMultiChildUpdateTypes');

View File

@ -9,8 +9,7 @@
* @providesModule ReactNativeDefaultInjection
* @flow
*/
"use strict";
'use strict';
/**
* Make sure `setTimeout`/`setInterval` are patched correctly.
@ -21,7 +20,6 @@ var EventPluginUtils = require('EventPluginUtils');
var IOSDefaultEventPluginOrder = require('IOSDefaultEventPluginOrder');
var IOSNativeBridgeEventPlugin = require('IOSNativeBridgeEventPlugin');
var NodeHandle = require('NodeHandle');
var ReactClass = require('ReactClass');
var ReactComponentEnvironment = require('ReactComponentEnvironment');
var ReactDefaultBatchingStrategy = require('ReactDefaultBatchingStrategy');
var ReactEmptyComponent = require('ReactEmptyComponent');

View File

@ -9,8 +9,7 @@
* @providesModule ReactNativeEventEmitter
* @flow
*/
"use strict";
'use strict';
var EventPluginHub = require('EventPluginHub');
var ReactEventEmitterMixin = require('ReactEventEmitterMixin');

View File

@ -21,7 +21,6 @@ var ReactUpdates = require('ReactUpdates');
var emptyObject = require('emptyObject');
var instantiateReactComponent = require('instantiateReactComponent');
var invariant = require('invariant');
var shouldUpdateReactComponent = require('shouldUpdateReactComponent');
function instanceNumberToChildRootID(rootNodeID, instanceNumber) {

View File

@ -9,8 +9,7 @@
* @providesModule ReactNativeReconcileTransaction
* @flow
*/
"use strict";
'use strict';
var CallbackQueue = require('CallbackQueue');
var PooledClass = require('PooledClass');

View File

@ -19,8 +19,11 @@ ReactNativeViewAttributes.UIView = {
pointerEvents: true,
accessible: true,
accessibilityLabel: true,
accessibilityTraits: true,
testID: true,
onLayout: true,
onAccessibilityTap: true,
onMagicTap: true,
};
ReactNativeViewAttributes.RCTView = merge(

View File

@ -10,9 +10,8 @@
* @flow
*/
"use strict";
'use strict';
var ReactElement = require('ReactElement');
var ReactNativeBaseComponent = require('ReactNativeBaseComponent');
// See also ReactNativeBaseComponent

View File

@ -31,7 +31,7 @@ var Settings = {
},
watchKeys(keys: string | Array<string>, callback: Function): number {
if (typeof keys == 'string') {
if (typeof keys === 'string') {
keys = [keys];
}
@ -41,7 +41,7 @@ var Settings = {
);
var sid = subscriptions.length;
subscriptions.push({keys: keys, callback: callback})
subscriptions.push({keys: keys, callback: callback});
return sid;
},
@ -52,15 +52,14 @@ var Settings = {
},
_sendObservations(body: Object) {
var _this = this;
Object.keys(body).forEach((key) => {
var newValue = body[key];
var didChange = _this._settings[key] !== newValue;
_this._settings[key] = newValue;
var didChange = this._settings[key] !== newValue;
this._settings[key] = newValue;
if (didChange) {
subscriptions.forEach((sub) => {
if (~sub.keys.indexOf(key) && sub.callback) {
if (sub.keys.indexOf(key) !== -1 && sub.callback) {
sub.callback();
}
});

View File

@ -9,12 +9,11 @@
* @providesModule EdgeInsetsPropType
* @flow
*/
'use strict'
'use strict';
var PropTypes = require('ReactPropTypes');
var createStrictShapeTypeChecker = require('createStrictShapeTypeChecker');
var insetsDiffer = require('insetsDiffer');
var EdgeInsetsPropType = createStrictShapeTypeChecker({
top: PropTypes.number,

View File

@ -9,12 +9,11 @@
* @providesModule PointPropType
* @flow
*/
'use strict'
'use strict';
var PropTypes = require('ReactPropTypes');
var createStrictShapeTypeChecker = require('createStrictShapeTypeChecker');
var pointsDiffer = require('pointsDiffer');
var PointPropType = createStrictShapeTypeChecker({
x: PropTypes.number,

View File

@ -8,6 +8,7 @@
*
* @providesModule ErrorUtils
*/
/* eslint-disable consistent-this, global-strict */
var GLOBAL = this;

View File

@ -3,6 +3,7 @@
*
* @providesModule MatrixMath
*/
/* eslint-disable space-infix-ops */
'use strict';
var invariant = require('invariant');

View File

@ -9,7 +9,6 @@
* @providesModule RCTLog
* @flow
*/
/* globals nativeLoggingHook */
'use strict';
var invariant = require('invariant');

View File

@ -12,7 +12,6 @@
'use strict';
var ReactDefaultPerf = require('ReactDefaultPerf');
var ReactPerf = require('ReactPerf');
var invariant = require('invariant');

View File

@ -6,7 +6,7 @@
function execute(fun, context, args) {
return fun.apply(context, args);
};
}
function reportError(error) {
throw error;

View File

@ -7,6 +7,7 @@
/**
* Cannot "use strict" because we must use eval in this file.
*/
/* eslint-disable global-strict */
var keyOf = require('keyOf');
@ -372,7 +373,7 @@ var MatrixOpsInitial = {
var setNextValAndDetectChange = function(name, tmpVarName) {
return (
' if (!didChange) {\n' +
' var prevVal = result.' + name +';\n' +
' var prevVal = result.' + name + ';\n' +
' result.' + name + ' = ' + tmpVarName + ';\n' +
' didChange = didChange || (' + tmpVarName + ' !== prevVal);\n' +
' } else {\n' +

View File

@ -45,4 +45,3 @@ var truncate = function(
};
module.exports = truncate;

View File

@ -141,6 +141,7 @@ RCT_EXTERN BOOL RCTCopyProperty(id target, id source, NSString *keyPath);
* Underlying implementations of RCT_XXX_CONVERTER macros. Ignore these.
*/
RCT_EXTERN NSNumber *RCTConvertEnumValue(const char *, NSDictionary *, NSNumber *, id);
RCT_EXTERN NSNumber *RCTConvertMultiEnumValue(const char *, NSDictionary *, NSNumber *, id);
RCT_EXTERN NSArray *RCTConvertArrayValue(SEL, id);
RCT_EXTERN void RCTLogConvertError(id, const char *);
@ -194,6 +195,21 @@ RCT_CUSTOM_CONVERTER(type, type, [[self NSNumber:json] getter])
return [RCTConvertEnumValue(#type, mapping, @(default), json) getter]; \
}
/**
* This macro is used for creating converters for enum types for
* multiple enum values combined with | operator
*/
#define RCT_MULTI_ENUM_CONVERTER(type, values, default, getter) \
+ (type)type:(id)json \
{ \
static NSDictionary *mapping; \
static dispatch_once_t onceToken; \
dispatch_once(&onceToken, ^{ \
mapping = values; \
}); \
return [RCTConvertMultiEnumValue(#type, mapping, @(default), json) getter]; \
}
/**
* This macro is used for creating converter functions for typed arrays.
*/

View File

@ -175,6 +175,22 @@ NSNumber *RCTConvertEnumValue(const char *typeName, NSDictionary *mapping, NSNum
return value ?: defaultValue;
}
NSNumber *RCTConvertMultiEnumValue(const char *typeName, NSDictionary *mapping, NSNumber *defaultValue, id json)
{
if ([json isKindOfClass:[NSArray class]]) {
if ([json count] == 0) {
return defaultValue;
}
long long result = 0;
for (id arrayElement in json) {
NSNumber *value = RCTConvertEnumValue(typeName, mapping, defaultValue, arrayElement);
result |= [value longLongValue];
}
return @(result);
}
return RCTConvertEnumValue(typeName, mapping, defaultValue, json);
}
RCT_ENUM_CONVERTER(NSTextAlignment, (@{
@"auto": @(NSTextAlignmentNatural),
@"left": @(NSTextAlignmentLeft),

View File

@ -1309,6 +1309,12 @@ RCT_EXPORT_METHOD(clearJSResponder)
@"topLoadingError": @{
@"registrationName": @"onLoadingError"
},
@"topAccessibilityTap": @{
@"registrationName": @"onAccessibilityTap"
},
@"topMagicTap": @{
@"registrationName": @"onMagicTap"
},
} mutableCopy];
[_viewManagers enumerateKeysAndObjectsUsingBlock:^(NSString *name, RCTViewManager *manager, BOOL *stop) {

View File

@ -15,8 +15,14 @@
@protocol RCTAutoInsetsProtocol;
@class RCTView;
typedef void (^RCTViewEventHandler)(RCTView *view);
@interface RCTView : UIView
@property (nonatomic, copy) RCTViewEventHandler accessibilityTapHandler;
@property (nonatomic, copy) RCTViewEventHandler magicTapHandler;
/**
* Used to control how touch events are processed.
*/

View File

@ -167,6 +167,26 @@ static NSString *RCTRecursiveAccessibilityLabel(UIView *view)
}
}
- (BOOL)accessibilityActivate
{
if (self.accessibilityTapHandler) {
self.accessibilityTapHandler(self);
return YES;
} else {
return NO;
}
}
- (BOOL)accessibilityPerformMagicTap
{
if (self.magicTapHandler) {
self.magicTapHandler(self);
return YES;
} else {
return NO;
}
}
#pragma mark - Statics for dealing with layoutGuides
+ (void)autoAdjustInsetsForView:(UIView<RCTAutoInsetsProtocol> *)parentView

View File

@ -17,6 +17,31 @@
#import "RCTUIManager.h"
#import "RCTUtils.h"
#import "RCTView.h"
#import "UIView+React.h"
@implementation RCTConvert(UIAccessibilityTraits)
RCT_MULTI_ENUM_CONVERTER(UIAccessibilityTraits, (@{
@"none": @(UIAccessibilityTraitNone),
@"button": @(UIAccessibilityTraitButton),
@"link": @(UIAccessibilityTraitLink),
@"header": @(UIAccessibilityTraitHeader),
@"search": @(UIAccessibilityTraitSearchField),
@"image": @(UIAccessibilityTraitImage),
@"selected": @(UIAccessibilityTraitSelected),
@"plays": @(UIAccessibilityTraitPlaysSound),
@"key": @(UIAccessibilityTraitKeyboardKey),
@"text": @(UIAccessibilityTraitStaticText),
@"summary": @(UIAccessibilityTraitSummaryElement),
@"disabled": @(UIAccessibilityTraitNotEnabled),
@"frequentUpdates": @(UIAccessibilityTraitUpdatesFrequently),
@"startsMedia": @(UIAccessibilityTraitStartsMediaSession),
@"adjustable": @(UIAccessibilityTraitAdjustable),
@"allowsDirectInteraction": @(UIAccessibilityTraitAllowsDirectInteraction),
@"pageTurn": @(UIAccessibilityTraitCausesPageTurn),
}), UIAccessibilityTraitNone, unsignedLongLongValue)
@end
@implementation RCTViewManager
@ -67,6 +92,7 @@ RCT_EXPORT_MODULE()
#pragma mark - View properties
RCT_EXPORT_VIEW_PROPERTY(accessibilityLabel, NSString)
RCT_EXPORT_VIEW_PROPERTY(accessibilityTraits, UIAccessibilityTraits)
RCT_EXPORT_VIEW_PROPERTY(backgroundColor, UIColor)
RCT_REMAP_VIEW_PROPERTY(accessible, isAccessibilityElement, BOOL)
RCT_REMAP_VIEW_PROPERTY(testID, accessibilityIdentifier, NSString)
@ -146,6 +172,27 @@ RCT_CUSTOM_VIEW_PROPERTY(borderWidth, CGFloat, RCTView)
view.layer.borderWidth = json ? [RCTConvert CGFloat:json] : defaultView.layer.borderWidth;
}
}
RCT_CUSTOM_VIEW_PROPERTY(onAccessibilityTap, BOOL, RCTView)
{
view.accessibilityTapHandler = [self eventHandlerWithName:@"topAccessibilityTap" json:json];
}
RCT_CUSTOM_VIEW_PROPERTY(onMagicTap, BOOL, RCTView)
{
view.magicTapHandler = [self eventHandlerWithName:@"topMagicTap" json:json];
}
- (RCTViewEventHandler)eventHandlerWithName:(NSString *)eventName json:(id)json
{
RCTViewEventHandler handler = nil;
if ([RCTConvert BOOL:json]) {
__weak RCTViewManager *weakSelf = self;
handler = ^(RCTView *tappedView) {
NSDictionary *body = @{ @"target": tappedView.reactTag };
[weakSelf.bridge.eventDispatcher sendInputEventWithName:eventName body:body];
};
}
return handler;
}
#define RCT_VIEW_BORDER_PROPERTY(SIDE) \
RCT_CUSTOM_VIEW_PROPERTY(border##SIDE##Width, CGFloat, RCTView) \

View File

@ -36,7 +36,7 @@
],
"scripts": {
"test": "jest",
"lint": "node linter.js Examples/",
"lint": "node linter.js Examples/ Libraries/",
"start": "./packager/packager.sh"
},
"bin": {