mirror of
https://github.com/status-im/react-native.git
synced 2025-01-12 18:44:25 +00:00
Updates from Thu Feb 26
- [Children] Expose React.Children like web React | James Ide - Remove touch handler assertions - not always true | Tadeu Zagallo - [treehouse] Add support for clear button on UITextFields | Sumeet Vaidya - [Touch] Suite of touchable events on TouchableHighlight/Opacity | James Ide - [Images] Bail out when GIF data is in unexpected format instead of crashing | James Ide
This commit is contained in:
parent
9bebc7e519
commit
258c6b1b54
@ -12,6 +12,7 @@ var {
|
||||
StyleSheet,
|
||||
Text,
|
||||
TouchableHighlight,
|
||||
TouchableOpacity,
|
||||
View,
|
||||
} = React;
|
||||
|
||||
@ -57,6 +58,13 @@ exports.examples = [
|
||||
render: function() {
|
||||
return <TextOnPressBox />;
|
||||
},
|
||||
}, {
|
||||
title: 'Touchable feedback events',
|
||||
description: '<Touchable*> components accept onPress, onPressIn, ' +
|
||||
'onPressOut, and onLongPress as props.',
|
||||
render: function() {
|
||||
return <TouchableFeedbackEvents />;
|
||||
},
|
||||
}];
|
||||
|
||||
var TextOnPressBox = React.createClass({
|
||||
@ -95,11 +103,46 @@ var TextOnPressBox = React.createClass({
|
||||
}
|
||||
});
|
||||
|
||||
var TouchableFeedbackEvents = React.createClass({
|
||||
getInitialState: function() {
|
||||
return {
|
||||
eventLog: [],
|
||||
};
|
||||
},
|
||||
render: function() {
|
||||
return (
|
||||
<View>
|
||||
<View style={[styles.row, {justifyContent: 'center'}]}>
|
||||
<TouchableOpacity
|
||||
style={styles.wrapper}
|
||||
onPress={() => this._appendEvent('press')}
|
||||
onPressIn={() => this._appendEvent('pressIn')}
|
||||
onPressOut={() => this._appendEvent('pressOut')}
|
||||
onLongPress={() => this._appendEvent('longPress')}>
|
||||
<Text style={styles.button}>
|
||||
Press Me
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
<View style={styles.eventLogBox}>
|
||||
{this.state.eventLog.map((e, ii) => <Text key={ii}>{e}</Text>)}
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
},
|
||||
_appendEvent: function(eventName) {
|
||||
var limit = 6;
|
||||
var eventLog = this.state.eventLog.slice(0, limit - 1);
|
||||
eventLog.unshift(eventName);
|
||||
this.setState({eventLog});
|
||||
},
|
||||
});
|
||||
|
||||
var heartImage = {uri: 'https://pbs.twimg.com/media/BlXBfT3CQAA6cVZ.png:small'};
|
||||
|
||||
var styles = StyleSheet.create({
|
||||
row: {
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
flexDirection: 'row',
|
||||
},
|
||||
icon: {
|
||||
@ -113,6 +156,9 @@ var styles = StyleSheet.create({
|
||||
text: {
|
||||
fontSize: 16,
|
||||
},
|
||||
button: {
|
||||
color: '#007AFF',
|
||||
},
|
||||
wrapper: {
|
||||
borderRadius: 8,
|
||||
},
|
||||
@ -127,6 +173,14 @@ var styles = StyleSheet.create({
|
||||
borderColor: '#f0f0f0',
|
||||
backgroundColor: '#f9f9f9',
|
||||
},
|
||||
eventLogBox: {
|
||||
padding: 10,
|
||||
margin: 10,
|
||||
height: 120,
|
||||
borderWidth: 1 / PixelRatio.get(),
|
||||
borderColor: '#f0f0f0',
|
||||
backgroundColor: '#f9f9f9',
|
||||
},
|
||||
textBlock: {
|
||||
fontWeight: 'bold',
|
||||
color: 'blue',
|
||||
|
@ -68,6 +68,15 @@ var autoCapitalizeMode = {
|
||||
characters: nativeConstants.AllCharacters
|
||||
};
|
||||
|
||||
var clearButtonModeConstants = NativeModulesDeprecated.RKUIManager.UITextField.clearButtonMode;
|
||||
|
||||
var clearButtonModeTypes = {
|
||||
never: clearButtonModeConstants.Never,
|
||||
whileEditing: clearButtonModeConstants.WhileEditing,
|
||||
unlessEditing: clearButtonModeConstants.UnlessEditing,
|
||||
always: clearButtonModeConstants.Always,
|
||||
};
|
||||
|
||||
var keyboardType = {
|
||||
default: 'default',
|
||||
numeric: 'numeric',
|
||||
@ -90,6 +99,7 @@ var RKTextViewAttributes = merge(ReactIOSViewAttributes.UIView, {
|
||||
var RKTextFieldAttributes = merge(RKTextViewAttributes, {
|
||||
caretHidden: true,
|
||||
enabled: true,
|
||||
clearButtonMode: true,
|
||||
});
|
||||
|
||||
var onlyMultiline = {
|
||||
@ -105,6 +115,7 @@ var notMultiline = {
|
||||
var TextInput = React.createClass({
|
||||
statics: {
|
||||
autoCapitalizeMode: autoCapitalizeMode,
|
||||
clearButtonModeTypes: clearButtonModeTypes,
|
||||
keyboardType: keyboardType,
|
||||
},
|
||||
|
||||
@ -188,6 +199,10 @@ var TextInput = React.createClass({
|
||||
* and/or laggy typing, depending on how you process onChange events.
|
||||
*/
|
||||
controlled: PropTypes.bool,
|
||||
/**
|
||||
* When the clear button should appear on the right side of the text view
|
||||
*/
|
||||
clearButtonMode: PropTypes.oneOf(getObjectValues(clearButtonModeTypes)),
|
||||
|
||||
style: Text.stylePropType,
|
||||
},
|
||||
@ -316,6 +331,7 @@ var TextInput = React.createClass({
|
||||
text={this.state.bufferedValue}
|
||||
autoCapitalize={this.props.autoCapitalize}
|
||||
autoCorrect={this.props.autoCorrect}
|
||||
clearButtonMode={this.props.clearButtonMode}
|
||||
/>;
|
||||
} else {
|
||||
for (var propKey in notMultiline) {
|
||||
|
22
Libraries/Components/Touchable/TouchableFeedbackPropType.js
Normal file
22
Libraries/Components/Touchable/TouchableFeedbackPropType.js
Normal file
@ -0,0 +1,22 @@
|
||||
/**
|
||||
* Copyright 2004-present Facebook. All Rights Reserved.
|
||||
*
|
||||
* @providesModule TouchableFeedbackPropType
|
||||
* @flow
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var { PropTypes } = require('React');
|
||||
|
||||
var TouchableFeedbackPropType = {
|
||||
/**
|
||||
* Called when the touch is released, but not if cancelled (e.g. by a scroll
|
||||
* that steals the responder lock).
|
||||
*/
|
||||
onPress: PropTypes.func,
|
||||
onPressIn: PropTypes.func,
|
||||
onPressOut: PropTypes.func,
|
||||
onLongPress: PropTypes.func,
|
||||
};
|
||||
|
||||
module.exports = TouchableFeedbackPropType;
|
@ -11,6 +11,7 @@ var ReactIOSViewAttributes = require('ReactIOSViewAttributes');
|
||||
var StyleSheet = require('StyleSheet');
|
||||
var TimerMixin = require('TimerMixin');
|
||||
var Touchable = require('Touchable');
|
||||
var TouchableFeedbackPropType = require('TouchableFeedbackPropType');
|
||||
var View = require('View');
|
||||
|
||||
var cloneWithProps = require('cloneWithProps');
|
||||
@ -50,6 +51,7 @@ var DEFAULT_PROPS = {
|
||||
|
||||
var TouchableHighlight = React.createClass({
|
||||
propTypes: {
|
||||
...TouchableFeedbackPropType,
|
||||
/**
|
||||
* Called when the touch is released, but not if cancelled (e.g. by
|
||||
* a scroll that steals the responder lock).
|
||||
@ -127,12 +129,14 @@ var TouchableHighlight = React.createClass({
|
||||
this.clearTimeout(this._hideTimeout);
|
||||
this._hideTimeout = null;
|
||||
this._showUnderlay();
|
||||
this.props.onPressIn && this.props.onPressIn();
|
||||
},
|
||||
|
||||
touchableHandleActivePressOut: function() {
|
||||
if (!this._hideTimeout) {
|
||||
this._hideUnderlay();
|
||||
}
|
||||
this.props.onPressOut && this.props.onPressOut();
|
||||
},
|
||||
|
||||
touchableHandlePress: function() {
|
||||
@ -142,6 +146,10 @@ var TouchableHighlight = React.createClass({
|
||||
this.props.onPress && this.props.onPress();
|
||||
},
|
||||
|
||||
touchableHandleLongPress: function() {
|
||||
this.props.onLongPress && this.props.onLongPress();
|
||||
},
|
||||
|
||||
touchableGetPressRectOffset: function() {
|
||||
return PRESS_RECT_OFFSET; // Always make sure to predeclare a constant!
|
||||
},
|
||||
|
@ -9,6 +9,7 @@ var NativeMethodsMixin = require('NativeMethodsMixin');
|
||||
var POPAnimationMixin = require('POPAnimationMixin');
|
||||
var React = require('React');
|
||||
var Touchable = require('Touchable');
|
||||
var TouchableFeedbackPropType = require('TouchableFeedbackPropType');
|
||||
|
||||
var cloneWithProps = require('cloneWithProps');
|
||||
var ensureComponentIsNative = require('ensureComponentIsNative');
|
||||
@ -41,11 +42,7 @@ var TouchableOpacity = React.createClass({
|
||||
mixins: [Touchable.Mixin, NativeMethodsMixin, POPAnimationMixin],
|
||||
|
||||
propTypes: {
|
||||
/**
|
||||
* Called when the touch is released, but not if cancelled (e.g. by
|
||||
* a scroll that steals the responder lock).
|
||||
*/
|
||||
onPress: React.PropTypes.func,
|
||||
...TouchableFeedbackPropType,
|
||||
/**
|
||||
* Determines what the opacity of the wrapped view should be when touch is
|
||||
* active.
|
||||
@ -97,10 +94,12 @@ var TouchableOpacity = React.createClass({
|
||||
this.refs[CHILD_REF].setNativeProps({
|
||||
opacity: this.props.activeOpacity
|
||||
});
|
||||
this.props.onPressIn && this.props.onPressIn();
|
||||
},
|
||||
|
||||
touchableHandleActivePressOut: function() {
|
||||
this.setOpacityTo(1.0);
|
||||
this.props.onPressOut && this.props.onPressOut();
|
||||
},
|
||||
|
||||
touchableHandlePress: function() {
|
||||
@ -108,6 +107,10 @@ var TouchableOpacity = React.createClass({
|
||||
this.props.onPress && this.props.onPress();
|
||||
},
|
||||
|
||||
touchableHandleLongPress: function() {
|
||||
this.props.onLongPress && this.props.onLongPress();
|
||||
},
|
||||
|
||||
touchableGetPressRectOffset: function() {
|
||||
return PRESS_RECT_OFFSET; // Always make sure to predeclare a constant!
|
||||
},
|
||||
|
@ -7,7 +7,7 @@
|
||||
|
||||
var React = require('React');
|
||||
var Touchable = require('Touchable');
|
||||
var View = require('View');
|
||||
var TouchableFeedbackPropType = require('TouchableFeedbackPropType');
|
||||
|
||||
var copyProperties = require('copyProperties');
|
||||
var onlyChild = require('onlyChild');
|
||||
@ -29,12 +29,7 @@ var PRESS_RECT_OFFSET = {top: 20, left: 20, right: 20, bottom: 30};
|
||||
var TouchableWithoutFeedback = React.createClass({
|
||||
mixins: [Touchable.Mixin],
|
||||
|
||||
propTypes: {
|
||||
onPress: React.PropTypes.func,
|
||||
onPressIn: React.PropTypes.func,
|
||||
onPressOut: React.PropTypes.func,
|
||||
onLongPress: React.PropTypes.func,
|
||||
},
|
||||
propTypes: TouchableFeedbackPropType,
|
||||
|
||||
getInitialState: function() {
|
||||
return this.touchableGetInitialState();
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
var ReactChildren = require('ReactChildren');
|
||||
var ReactComponent = require('ReactComponent');
|
||||
var ReactCompositeComponent = require('ReactCompositeComponent');
|
||||
var ReactContext = require('ReactContext');
|
||||
@ -20,6 +21,7 @@ var ReactPropTypes = require('ReactPropTypes');
|
||||
|
||||
var deprecated = require('deprecated');
|
||||
var invariant = require('invariant');
|
||||
var onlyChild = require('onlyChild');
|
||||
|
||||
ReactIOSDefaultInjection.inject();
|
||||
|
||||
@ -73,6 +75,12 @@ var render = function(component, mountInto) {
|
||||
|
||||
var ReactIOS = {
|
||||
hasReactIOSInitialized: false,
|
||||
Children: {
|
||||
map: ReactChildren.map,
|
||||
forEach: ReactChildren.forEach,
|
||||
count: ReactChildren.count,
|
||||
only: onlyChild
|
||||
},
|
||||
PropTypes: ReactPropTypes,
|
||||
createClass: ReactCompositeComponent.createClass,
|
||||
createElement: createElement,
|
||||
|
@ -446,6 +446,9 @@ RCT_STRUCT_CONVERTER(CGAffineTransform, (@[@"a", @"b", @"c", @"d", @"tx", @"ty"]
|
||||
}
|
||||
|
||||
imageSource = CGImageSourceCreateWithData((CFDataRef)data, NULL);
|
||||
} else {
|
||||
RCTLogMustFix(@"Expected NSString or NSData for GIF, received %@: %@", [json class], json);
|
||||
return nil;
|
||||
}
|
||||
|
||||
if (!UTTypeConformsTo(CGImageSourceGetType(imageSource), kUTTypeGIF)) {
|
||||
|
@ -77,9 +77,10 @@ typedef NS_ENUM(NSInteger, RCTTouchEventType) {
|
||||
}
|
||||
targetView = targetView.superview;
|
||||
}
|
||||
|
||||
RCTAssert(targetView.reactTag && targetView.userInteractionEnabled,
|
||||
@"No react view found for touch - something went wrong.");
|
||||
|
||||
if (!targetView.reactTag || !targetView.userInteractionEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get new, unique touch id
|
||||
const NSUInteger RCTMaxTouches = 11; // This is the maximum supported by iDevices
|
||||
@ -113,7 +114,10 @@ typedef NS_ENUM(NSInteger, RCTTouchEventType) {
|
||||
{
|
||||
for (UITouch *touch in touches) {
|
||||
NSUInteger index = [_nativeTouches indexOfObject:touch];
|
||||
RCTAssert(index != NSNotFound, @"Touch is already removed. This is a critical bug.");
|
||||
if(index == NSNotFound) {
|
||||
continue;
|
||||
}
|
||||
|
||||
[_touchViews removeObjectAtIndex:index];
|
||||
[_nativeTouches removeObjectAtIndex:index];
|
||||
[_reactTouches removeObjectAtIndex:index];
|
||||
@ -159,10 +163,17 @@ typedef NS_ENUM(NSInteger, RCTTouchEventType) {
|
||||
NSMutableArray *changedIndexes = [[NSMutableArray alloc] init];
|
||||
for (UITouch *touch in touches) {
|
||||
NSInteger index = [_nativeTouches indexOfObject:touch];
|
||||
RCTAssert(index != NSNotFound, @"Touch not found. This is a critical bug.");
|
||||
if (index == NSNotFound) {
|
||||
continue;
|
||||
}
|
||||
|
||||
[self _updateReactTouchAtIndex:index];
|
||||
[changedIndexes addObject:@(index)];
|
||||
}
|
||||
|
||||
if (changedIndexes.count == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Deep copy the touches because they will be accessed from another thread
|
||||
// TODO: would it be safer to do this in the bridge or executor, rather than trusting caller?
|
||||
|
Loading…
x
Reference in New Issue
Block a user