mirror of
https://github.com/status-im/react-native.git
synced 2025-02-28 17:10:50 +00:00
Updates from Fri 5 Jun
This commit is contained in:
commit
0293def7a9
@ -281,7 +281,7 @@ var SearchScreen = React.createClass({
|
|||||||
renderRow={this.renderRow}
|
renderRow={this.renderRow}
|
||||||
onEndReached={this.onEndReached}
|
onEndReached={this.onEndReached}
|
||||||
automaticallyAdjustContentInsets={false}
|
automaticallyAdjustContentInsets={false}
|
||||||
keyboardDismissMode="onDrag"
|
keyboardDismissMode="on-drag"
|
||||||
keyboardShouldPersistTaps={true}
|
keyboardShouldPersistTaps={true}
|
||||||
showsVerticalScrollIndicator={false}
|
showsVerticalScrollIndicator={false}
|
||||||
/>;
|
/>;
|
||||||
|
83
Examples/UIExplorer/ProgressViewIOSExample.js
Normal file
83
Examples/UIExplorer/ProgressViewIOSExample.js
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
/**
|
||||||
|
* The examples provided by Facebook are for non-commercial testing and
|
||||||
|
* evaluation purposes only.
|
||||||
|
*
|
||||||
|
* Facebook reserves all rights not expressly granted.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||||
|
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* @flow
|
||||||
|
*/
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var React = require('react-native');
|
||||||
|
var {
|
||||||
|
ProgressViewIOS,
|
||||||
|
StyleSheet,
|
||||||
|
View,
|
||||||
|
} = React;
|
||||||
|
var TimerMixin = require('react-timer-mixin');
|
||||||
|
|
||||||
|
var ProgressViewExample = React.createClass({
|
||||||
|
mixins: [TimerMixin],
|
||||||
|
|
||||||
|
getInitialState() {
|
||||||
|
return {
|
||||||
|
progress: 0,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this.updateProgress();
|
||||||
|
},
|
||||||
|
|
||||||
|
updateProgress() {
|
||||||
|
var progress = this.state.progress + 0.01;
|
||||||
|
this.setState({ progress });
|
||||||
|
this.requestAnimationFrame(() => this.updateProgress());
|
||||||
|
},
|
||||||
|
|
||||||
|
getProgress(offset) {
|
||||||
|
var progress = this.state.progress + offset;
|
||||||
|
return Math.sin(progress % Math.PI) % 1;
|
||||||
|
},
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<View style={styles.container}>
|
||||||
|
<ProgressViewIOS style={styles.progressView} progress={this.getProgress(0)}/>
|
||||||
|
<ProgressViewIOS style={styles.progressView} progressTintColor="purple" progress={this.getProgress(0.2)}/>
|
||||||
|
<ProgressViewIOS style={styles.progressView} progressTintColor="red" progress={this.getProgress(0.4)}/>
|
||||||
|
<ProgressViewIOS style={styles.progressView} progressTintColor="orange" progress={this.getProgress(0.6)}/>
|
||||||
|
<ProgressViewIOS style={styles.progressView} progressTintColor="yellow" progress={this.getProgress(0.8)}/>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
exports.framework = 'React';
|
||||||
|
exports.title = 'ProgressViewIOS';
|
||||||
|
exports.description = 'ProgressViewIOS';
|
||||||
|
exports.examples = [{
|
||||||
|
title: 'ProgressViewIOS',
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<ProgressViewExample/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
|
||||||
|
var styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
marginTop: -20,
|
||||||
|
backgroundColor: 'transparent',
|
||||||
|
},
|
||||||
|
progressView: {
|
||||||
|
marginTop: 20,
|
||||||
|
}
|
||||||
|
});
|
@ -32,11 +32,11 @@ exports.examples = [{
|
|||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<View>
|
<View>
|
||||||
{Object.keys(StatusBarIOS.Style).map((key) =>
|
{['default', 'light-content'].map((style) =>
|
||||||
<TouchableHighlight style={styles.wrapper}
|
<TouchableHighlight style={styles.wrapper}
|
||||||
onPress={() => StatusBarIOS.setStyle(StatusBarIOS.Style[key])}>
|
onPress={() => StatusBarIOS.setStyle(style)}>
|
||||||
<View style={styles.button}>
|
<View style={styles.button}>
|
||||||
<Text>setStyle(StatusBarIOS.Style.{key})</Text>
|
<Text>setStyle('{style}')</Text>
|
||||||
</View>
|
</View>
|
||||||
</TouchableHighlight>
|
</TouchableHighlight>
|
||||||
)}
|
)}
|
||||||
@ -48,11 +48,11 @@ exports.examples = [{
|
|||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<View>
|
<View>
|
||||||
{Object.keys(StatusBarIOS.Style).map((key) =>
|
{['default', 'light-content'].map((style) =>
|
||||||
<TouchableHighlight style={styles.wrapper}
|
<TouchableHighlight style={styles.wrapper}
|
||||||
onPress={() => StatusBarIOS.setStyle(StatusBarIOS.Style[key], true)}>
|
onPress={() => StatusBarIOS.setStyle(style, true)}>
|
||||||
<View style={styles.button}>
|
<View style={styles.button}>
|
||||||
<Text>setStyle(StatusBarIOS.Style.{key}, true)</Text>
|
<Text>setStyle('{style}', true)</Text>
|
||||||
</View>
|
</View>
|
||||||
</TouchableHighlight>
|
</TouchableHighlight>
|
||||||
)}
|
)}
|
||||||
@ -64,18 +64,18 @@ exports.examples = [{
|
|||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<View>
|
<View>
|
||||||
{Object.keys(StatusBarIOS.Animation).map((key) =>
|
{['none', 'fade', 'slide'].map((animation) =>
|
||||||
<View>
|
<View>
|
||||||
<TouchableHighlight style={styles.wrapper}
|
<TouchableHighlight style={styles.wrapper}
|
||||||
onPress={() => StatusBarIOS.setHidden(true, StatusBarIOS.Animation[key])}>
|
onPress={() => StatusBarIOS.setHidden(true, animation)}>
|
||||||
<View style={styles.button}>
|
<View style={styles.button}>
|
||||||
<Text>setHidden(true, StatusBarIOS.Animation.{key})</Text>
|
<Text>setHidden(true, '{animation}')</Text>
|
||||||
</View>
|
</View>
|
||||||
</TouchableHighlight>
|
</TouchableHighlight>
|
||||||
<TouchableHighlight style={styles.wrapper}
|
<TouchableHighlight style={styles.wrapper}
|
||||||
onPress={() => StatusBarIOS.setHidden(false, StatusBarIOS.Animation[key])}>
|
onPress={() => StatusBarIOS.setHidden(false, animation)}>
|
||||||
<View style={styles.button}>
|
<View style={styles.button}>
|
||||||
<Text>setHidden(false, StatusBarIOS.Animation.{key})</Text>
|
<Text>setHidden(false, '{animation}')</Text>
|
||||||
</View>
|
</View>
|
||||||
</TouchableHighlight>
|
</TouchableHighlight>
|
||||||
</View>
|
</View>
|
||||||
|
@ -75,6 +75,14 @@ exports.examples = [
|
|||||||
render: function(): ReactElement {
|
render: function(): ReactElement {
|
||||||
return <TouchableFeedbackEvents />;
|
return <TouchableFeedbackEvents />;
|
||||||
},
|
},
|
||||||
|
}, {
|
||||||
|
title: 'Touchable delay for events',
|
||||||
|
description: '<Touchable*> components also accept delayPressIn, ' +
|
||||||
|
'delayPressOut, and delayLongPress as props. These props impact the ' +
|
||||||
|
'timing of feedback events.',
|
||||||
|
render: function(): ReactElement {
|
||||||
|
return <TouchableDelayEvents />;
|
||||||
|
},
|
||||||
}];
|
}];
|
||||||
|
|
||||||
var TextOnPressBox = React.createClass({
|
var TextOnPressBox = React.createClass({
|
||||||
@ -148,6 +156,44 @@ var TouchableFeedbackEvents = React.createClass({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var TouchableDelayEvents = React.createClass({
|
||||||
|
getInitialState: function() {
|
||||||
|
return {
|
||||||
|
eventLog: [],
|
||||||
|
};
|
||||||
|
},
|
||||||
|
render: function() {
|
||||||
|
return (
|
||||||
|
<View>
|
||||||
|
<View style={[styles.row, {justifyContent: 'center'}]}>
|
||||||
|
<TouchableOpacity
|
||||||
|
style={styles.wrapper}
|
||||||
|
onPress={() => this._appendEvent('press')}
|
||||||
|
delayPressIn={400}
|
||||||
|
onPressIn={() => this._appendEvent('pressIn - 400ms delay')}
|
||||||
|
delayPressOut={1000}
|
||||||
|
onPressOut={() => this._appendEvent('pressOut - 1000ms delay')}
|
||||||
|
delayLongPress={800}
|
||||||
|
onLongPress={() => this._appendEvent('longPress - 800ms delay')}>
|
||||||
|
<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 heartImage = {uri: 'https://pbs.twimg.com/media/BlXBfT3CQAA6cVZ.png:small'};
|
||||||
|
|
||||||
var styles = StyleSheet.create({
|
var styles = StyleSheet.create({
|
||||||
|
@ -50,6 +50,10 @@
|
|||||||
|
|
||||||
// jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
|
// jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
|
||||||
|
|
||||||
|
#if RUNNING_ON_CI
|
||||||
|
jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
|
||||||
|
#endif
|
||||||
|
|
||||||
RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
|
RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
|
||||||
moduleName:@"UIExplorerApp"
|
moduleName:@"UIExplorerApp"
|
||||||
launchOptions:launchOptions];
|
launchOptions:launchOptions];
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
<key>CFBundleExecutable</key>
|
<key>CFBundleExecutable</key>
|
||||||
<string>$(EXECUTABLE_NAME)</string>
|
<string>$(EXECUTABLE_NAME)</string>
|
||||||
<key>CFBundleIdentifier</key>
|
<key>CFBundleIdentifier</key>
|
||||||
<string>com.facebook.$(PRODUCT_NAME:rfc1034identifier)</string>
|
<string>com.facebook.internal.uiexplorer.local</string>
|
||||||
<key>CFBundleInfoDictionaryVersion</key>
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
<string>6.0</string>
|
<string>6.0</string>
|
||||||
<key>CFBundleName</key>
|
<key>CFBundleName</key>
|
||||||
@ -22,6 +22,8 @@
|
|||||||
<string>1</string>
|
<string>1</string>
|
||||||
<key>LSRequiresIPhoneOS</key>
|
<key>LSRequiresIPhoneOS</key>
|
||||||
<true/>
|
<true/>
|
||||||
|
<key>NSLocationWhenInUseUsageDescription</key>
|
||||||
|
<string>You need to add NSLocationWhenInUseUsageDescription key in Info.plist to enable geolocation, otherwise it is going to *fail silently*!</string>
|
||||||
<key>UILaunchStoryboardName</key>
|
<key>UILaunchStoryboardName</key>
|
||||||
<string>LaunchScreen</string>
|
<string>LaunchScreen</string>
|
||||||
<key>UIRequiredDeviceCapabilities</key>
|
<key>UIRequiredDeviceCapabilities</key>
|
||||||
@ -34,8 +36,6 @@
|
|||||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||||
</array>
|
</array>
|
||||||
<key>NSLocationWhenInUseUsageDescription</key>
|
|
||||||
<string>You need to add NSLocationWhenInUseUsageDescription key in Info.plist to enable geolocation, otherwise it is going to *fail silently*!</string>
|
|
||||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||||
<false/>
|
<false/>
|
||||||
</dict>
|
</dict>
|
||||||
|
@ -45,6 +45,7 @@ var COMPONENTS = [
|
|||||||
require('./NavigatorIOSColorsExample'),
|
require('./NavigatorIOSColorsExample'),
|
||||||
require('./NavigatorIOSExample'),
|
require('./NavigatorIOSExample'),
|
||||||
require('./PickerIOSExample'),
|
require('./PickerIOSExample'),
|
||||||
|
require('./ProgressViewIOSExample'),
|
||||||
require('./ScrollViewExample'),
|
require('./ScrollViewExample'),
|
||||||
require('./SegmentedControlIOSExample'),
|
require('./SegmentedControlIOSExample'),
|
||||||
require('./SliderIOSExample'),
|
require('./SliderIOSExample'),
|
||||||
@ -156,7 +157,7 @@ class UIExplorerList extends React.Component {
|
|||||||
renderSectionHeader={this._renderSectionHeader}
|
renderSectionHeader={this._renderSectionHeader}
|
||||||
keyboardShouldPersistTaps={true}
|
keyboardShouldPersistTaps={true}
|
||||||
automaticallyAdjustContentInsets={false}
|
automaticallyAdjustContentInsets={false}
|
||||||
keyboardDismissMode="onDrag"
|
keyboardDismissMode="on-drag"
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
|
@ -16,12 +16,19 @@ var {
|
|||||||
View,
|
View,
|
||||||
} = React;
|
} = React;
|
||||||
|
|
||||||
|
var deepDiffer = require('deepDiffer');
|
||||||
|
|
||||||
var DEBUG = false;
|
var DEBUG = false;
|
||||||
|
|
||||||
var KEY_1 = 'key_1';
|
var KEY_1 = 'key_1';
|
||||||
var VAL_1 = 'val_1';
|
var VAL_1 = 'val_1';
|
||||||
var KEY_2 = 'key_2';
|
var KEY_2 = 'key_2';
|
||||||
var VAL_2 = 'val_2';
|
var VAL_2 = 'val_2';
|
||||||
|
var KEY_MERGE = 'key_merge';
|
||||||
|
var VAL_MERGE_1 = {'foo': 1, 'bar': {'hoo': 1, 'boo': 1}, 'moo': {'a': 3}};
|
||||||
|
var VAL_MERGE_2 = {'bar': {'hoo': 2}, 'baz': 2, 'moo': {'a': 3}};
|
||||||
|
var VAL_MERGE_EXPECT =
|
||||||
|
{'foo': 1, 'bar': {'hoo': 2, 'boo': 1}, 'baz': 2, 'moo': {'a': 3}};
|
||||||
|
|
||||||
// setup in componentDidMount
|
// setup in componentDidMount
|
||||||
var done;
|
var done;
|
||||||
@ -40,8 +47,9 @@ function expectTrue(condition, message) {
|
|||||||
|
|
||||||
function expectEqual(lhs, rhs, testname) {
|
function expectEqual(lhs, rhs, testname) {
|
||||||
expectTrue(
|
expectTrue(
|
||||||
lhs === rhs,
|
!deepDiffer(lhs, rhs),
|
||||||
'Error in test ' + testname + ': expected ' + rhs + ', got ' + lhs
|
'Error in test ' + testname + ': expected\n' + JSON.stringify(rhs) +
|
||||||
|
'\ngot\n' + JSON.stringify(lhs)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,31 +101,46 @@ function testRemoveItem() {
|
|||||||
'Missing KEY_1 or KEY_2 in ' + '(' + result + ')'
|
'Missing KEY_1 or KEY_2 in ' + '(' + result + ')'
|
||||||
);
|
);
|
||||||
updateMessage('testRemoveItem - add two items');
|
updateMessage('testRemoveItem - add two items');
|
||||||
AsyncStorage.removeItem(KEY_1, (err) => {
|
AsyncStorage.removeItem(KEY_1, (err2) => {
|
||||||
expectAsyncNoError(err);
|
expectAsyncNoError(err2);
|
||||||
updateMessage('delete successful ');
|
updateMessage('delete successful ');
|
||||||
AsyncStorage.getItem(KEY_1, (err, result) => {
|
AsyncStorage.getItem(KEY_1, (err3, result2) => {
|
||||||
expectAsyncNoError(err);
|
expectAsyncNoError(err3);
|
||||||
expectEqual(
|
expectEqual(
|
||||||
result,
|
result2,
|
||||||
null,
|
null,
|
||||||
'testRemoveItem: key_1 present after delete'
|
'testRemoveItem: key_1 present after delete'
|
||||||
);
|
);
|
||||||
updateMessage('key properly removed ');
|
updateMessage('key properly removed ');
|
||||||
AsyncStorage.getAllKeys((err, result2) => {
|
AsyncStorage.getAllKeys((err4, result3) => {
|
||||||
expectAsyncNoError(err);
|
expectAsyncNoError(err4);
|
||||||
expectTrue(
|
expectTrue(
|
||||||
result2.indexOf(KEY_1) === -1,
|
result3.indexOf(KEY_1) === -1,
|
||||||
'Unexpected: KEY_1 present in ' + result2
|
'Unexpected: KEY_1 present in ' + result3
|
||||||
);
|
);
|
||||||
updateMessage('proper length returned.\nDone!');
|
updateMessage('proper length returned.');
|
||||||
|
runTestCase('should merge values', testMerge);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function testMerge() {
|
||||||
|
AsyncStorage.setItem(KEY_MERGE, JSON.stringify(VAL_MERGE_1), (err1) => {
|
||||||
|
expectAsyncNoError(err1);
|
||||||
|
AsyncStorage.mergeItem(KEY_MERGE, JSON.stringify(VAL_MERGE_2), (err2) => {
|
||||||
|
expectAsyncNoError(err2);
|
||||||
|
AsyncStorage.getItem(KEY_MERGE, (err3, result) => {
|
||||||
|
expectAsyncNoError(err3);
|
||||||
|
expectEqual(JSON.parse(result), VAL_MERGE_EXPECT, 'testMerge');
|
||||||
|
updateMessage('objects deeply merged\nDone!');
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var AsyncStorageTest = React.createClass({
|
var AsyncStorageTest = React.createClass({
|
||||||
|
@ -7,7 +7,6 @@
|
|||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
*
|
*
|
||||||
* @providesModule POPAnimation
|
* @providesModule POPAnimation
|
||||||
* @flow
|
|
||||||
*/
|
*/
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
@ -17,7 +16,7 @@ if (!RCTPOPAnimationManager) {
|
|||||||
// workaround to enable its availability to be determined at runtime.
|
// workaround to enable its availability to be determined at runtime.
|
||||||
// For Flow let's pretend like we always export POPAnimation
|
// For Flow let's pretend like we always export POPAnimation
|
||||||
// so all our users don't need to do null checks
|
// so all our users don't need to do null checks
|
||||||
module.exports = ((null: any): typeof POPAnimation);
|
module.exports = null;
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
var ReactPropTypes = require('ReactPropTypes');
|
var ReactPropTypes = require('ReactPropTypes');
|
||||||
|
@ -120,7 +120,7 @@ var DatePickerIOS = React.createClass({
|
|||||||
<View style={props.style}>
|
<View style={props.style}>
|
||||||
<RCTDatePickerIOS
|
<RCTDatePickerIOS
|
||||||
ref={DATEPICKER}
|
ref={DATEPICKER}
|
||||||
style={styles.rkDatePickerIOS}
|
style={styles.datePickerIOS}
|
||||||
date={props.date.getTime()}
|
date={props.date.getTime()}
|
||||||
maximumDate={
|
maximumDate={
|
||||||
props.maximumDate ? props.maximumDate.getTime() : undefined
|
props.maximumDate ? props.maximumDate.getTime() : undefined
|
||||||
@ -128,7 +128,7 @@ var DatePickerIOS = React.createClass({
|
|||||||
minimumDate={
|
minimumDate={
|
||||||
props.minimumDate ? props.minimumDate.getTime() : undefined
|
props.minimumDate ? props.minimumDate.getTime() : undefined
|
||||||
}
|
}
|
||||||
mode={RCTDatePickerIOSConsts.DatePickerModes[props.mode]}
|
mode={props.mode}
|
||||||
minuteInterval={props.minuteInterval}
|
minuteInterval={props.minuteInterval}
|
||||||
timeZoneOffsetInMinutes={props.timeZoneOffsetInMinutes}
|
timeZoneOffsetInMinutes={props.timeZoneOffsetInMinutes}
|
||||||
onChange={this._onChange}
|
onChange={this._onChange}
|
||||||
@ -139,7 +139,7 @@ var DatePickerIOS = React.createClass({
|
|||||||
});
|
});
|
||||||
|
|
||||||
var styles = StyleSheet.create({
|
var styles = StyleSheet.create({
|
||||||
rkDatePickerIOS: {
|
datePickerIOS: {
|
||||||
height: RCTDatePickerIOSConsts.ComponentHeight,
|
height: RCTDatePickerIOSConsts.ComponentHeight,
|
||||||
width: RCTDatePickerIOSConsts.ComponentWidth,
|
width: RCTDatePickerIOSConsts.ComponentWidth,
|
||||||
},
|
},
|
||||||
|
@ -0,0 +1,49 @@
|
|||||||
|
|
||||||
|
/**
|
||||||
|
* 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 ProgressViewIOS
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var React = require('React');
|
||||||
|
var StyleSheet = require('StyleSheet');
|
||||||
|
var Text = require('Text');
|
||||||
|
var View = require('View');
|
||||||
|
|
||||||
|
var DummyProgressViewIOS = React.createClass({
|
||||||
|
render: function() {
|
||||||
|
return (
|
||||||
|
<View style={[styles.dummy, this.props.style]}>
|
||||||
|
<Text style={styles.text}>
|
||||||
|
ProgressViewIOS is not supported on this platform!
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
var styles = StyleSheet.create({
|
||||||
|
dummy: {
|
||||||
|
width: 120,
|
||||||
|
height: 20,
|
||||||
|
backgroundColor: '#ffbcbc',
|
||||||
|
borderWidth: 1,
|
||||||
|
borderColor: 'red',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
},
|
||||||
|
text: {
|
||||||
|
color: '#333333',
|
||||||
|
margin: 5,
|
||||||
|
fontSize: 10,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = DummyProgressViewIOS;
|
83
Libraries/Components/ProgressViewIOS/ProgressViewIOS.ios.js
Normal file
83
Libraries/Components/ProgressViewIOS/ProgressViewIOS.ios.js
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
/**
|
||||||
|
* 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 ProgressViewIOS
|
||||||
|
* @flow
|
||||||
|
*/
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var Image = require('Image');
|
||||||
|
var NativeMethodsMixin = require('NativeMethodsMixin');
|
||||||
|
var NativeModules = require('NativeModules');
|
||||||
|
var PropTypes = require('ReactPropTypes');
|
||||||
|
var React = require('React');
|
||||||
|
var StyleSheet = require('StyleSheet');
|
||||||
|
|
||||||
|
var requireNativeComponent = require('requireNativeComponent');
|
||||||
|
var verifyPropTypes = require('verifyPropTypes');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use `ProgressViewIOS` to render a UIProgressView on iOS.
|
||||||
|
*/
|
||||||
|
var ProgressViewIOS = React.createClass({
|
||||||
|
mixins: [NativeMethodsMixin],
|
||||||
|
|
||||||
|
propTypes: {
|
||||||
|
/**
|
||||||
|
* The progress bar style.
|
||||||
|
*/
|
||||||
|
progressViewStyle: PropTypes.oneOf(['default', 'bar']),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The progress value (between 0 and 1).
|
||||||
|
*/
|
||||||
|
progress: PropTypes.number,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The tint color of the progress bar itself.
|
||||||
|
*/
|
||||||
|
progressTintColor: PropTypes.string,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The tint color of the progress bar track.
|
||||||
|
*/
|
||||||
|
trackTintColor: PropTypes.string,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A stretchable image to display as the progress bar.
|
||||||
|
*/
|
||||||
|
progressImage: Image.propTypes.source,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A stretchable image to display behind the progress bar.
|
||||||
|
*/
|
||||||
|
trackImage: Image.propTypes.source,
|
||||||
|
},
|
||||||
|
|
||||||
|
render: function() {
|
||||||
|
return (
|
||||||
|
<RCTProgressView
|
||||||
|
{...this.props}
|
||||||
|
style={[styles.progressView, this.props.style]}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var styles = StyleSheet.create({
|
||||||
|
progressView: {
|
||||||
|
height: NativeModules.ProgressViewManager.ComponentHeight
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
var RCTProgressView = requireNativeComponent(
|
||||||
|
'RCTProgressView',
|
||||||
|
ProgressViewIOS
|
||||||
|
);
|
||||||
|
|
||||||
|
module.exports = ProgressViewIOS;
|
@ -38,12 +38,6 @@ var PropTypes = React.PropTypes;
|
|||||||
var SCROLLVIEW = 'ScrollView';
|
var SCROLLVIEW = 'ScrollView';
|
||||||
var INNERVIEW = 'InnerScrollView';
|
var INNERVIEW = 'InnerScrollView';
|
||||||
|
|
||||||
var keyboardDismissModeConstants = {
|
|
||||||
'none': RCTScrollViewConsts.KeyboardDismissMode.None, // default
|
|
||||||
'interactive': RCTScrollViewConsts.KeyboardDismissMode.Interactive,
|
|
||||||
'onDrag': RCTScrollViewConsts.KeyboardDismissMode.OnDrag,
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component that wraps platform ScrollView while providing
|
* Component that wraps platform ScrollView while providing
|
||||||
* integration with touch locking "responder" system.
|
* integration with touch locking "responder" system.
|
||||||
@ -147,7 +141,7 @@ var ScrollView = React.createClass({
|
|||||||
keyboardDismissMode: PropTypes.oneOf([
|
keyboardDismissMode: PropTypes.oneOf([
|
||||||
'none', // default
|
'none', // default
|
||||||
'interactive',
|
'interactive',
|
||||||
'onDrag',
|
'on-drag',
|
||||||
]),
|
]),
|
||||||
/**
|
/**
|
||||||
* When false, tapping outside of the focused text input when the keyboard
|
* When false, tapping outside of the focused text input when the keyboard
|
||||||
@ -287,9 +281,6 @@ var ScrollView = React.createClass({
|
|||||||
...this.props,
|
...this.props,
|
||||||
alwaysBounceHorizontal,
|
alwaysBounceHorizontal,
|
||||||
alwaysBounceVertical,
|
alwaysBounceVertical,
|
||||||
keyboardDismissMode: this.props.keyboardDismissMode ?
|
|
||||||
keyboardDismissModeConstants[this.props.keyboardDismissMode] :
|
|
||||||
undefined,
|
|
||||||
style: ([styles.base, this.props.style]: ?Array<any>),
|
style: ([styles.base, this.props.style]: ?Array<any>),
|
||||||
onTouchStart: this.scrollResponderHandleTouchStart,
|
onTouchStart: this.scrollResponderHandleTouchStart,
|
||||||
onTouchMove: this.scrollResponderHandleTouchMove,
|
onTouchMove: this.scrollResponderHandleTouchMove,
|
||||||
@ -318,6 +309,13 @@ var ScrollView = React.createClass({
|
|||||||
} else {
|
} else {
|
||||||
ScrollViewClass = AndroidScrollView;
|
ScrollViewClass = AndroidScrollView;
|
||||||
}
|
}
|
||||||
|
var keyboardDismissModeConstants = {
|
||||||
|
'none': RCTScrollViewConsts.KeyboardDismissMode.None, // default
|
||||||
|
'interactive': RCTScrollViewConsts.KeyboardDismissMode.Interactive,
|
||||||
|
'on-drag': RCTScrollViewConsts.KeyboardDismissMode.OnDrag,
|
||||||
|
};
|
||||||
|
props.keyboardDismissMode = props.keyboardDismissMode ?
|
||||||
|
keyboardDismissModeConstants[props.keyboardDismissMode] : undefined;
|
||||||
}
|
}
|
||||||
invariant(
|
invariant(
|
||||||
ScrollViewClass !== undefined,
|
ScrollViewClass !== undefined,
|
||||||
|
@ -17,7 +17,7 @@ var StyleSheet = require('StyleSheet');
|
|||||||
var Text = require('Text');
|
var Text = require('Text');
|
||||||
var View = require('View');
|
var View = require('View');
|
||||||
|
|
||||||
var Dummy = React.createClass({
|
var DummySegmentedControlIOS = React.createClass({
|
||||||
render: function() {
|
render: function() {
|
||||||
return (
|
return (
|
||||||
<View style={[styles.dummy, this.props.style]}>
|
<View style={[styles.dummy, this.props.style]}>
|
||||||
@ -46,4 +46,4 @@ var styles = StyleSheet.create({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = Dummy;
|
module.exports = DummySegmentedControlIOS;
|
||||||
|
@ -108,13 +108,7 @@ var styles = StyleSheet.create({
|
|||||||
|
|
||||||
var RCTSegmentedControl = requireNativeComponent(
|
var RCTSegmentedControl = requireNativeComponent(
|
||||||
'RCTSegmentedControl',
|
'RCTSegmentedControl',
|
||||||
null
|
SegmentedControlIOS
|
||||||
);
|
);
|
||||||
if (__DEV__) {
|
|
||||||
verifyPropTypes(
|
|
||||||
RCTSegmentedControl,
|
|
||||||
RCTSegmentedControl.viewConfig
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = SegmentedControlIOS;
|
module.exports = SegmentedControlIOS;
|
||||||
|
@ -13,26 +13,26 @@
|
|||||||
|
|
||||||
var RCTStatusBarManager = require('NativeModules').StatusBarManager;
|
var RCTStatusBarManager = require('NativeModules').StatusBarManager;
|
||||||
|
|
||||||
|
type StatusBarStyle = $Enum<{
|
||||||
|
'default': string,
|
||||||
|
'light-content': string,
|
||||||
|
}>;
|
||||||
|
|
||||||
|
type StatusBarAnimation = $Enum<{
|
||||||
|
'none': string,
|
||||||
|
'fade': string,
|
||||||
|
'slide': string,
|
||||||
|
}>;
|
||||||
|
|
||||||
var StatusBarIOS = {
|
var StatusBarIOS = {
|
||||||
|
|
||||||
Style: {
|
setStyle(style: StatusBarStyle, animated?: boolean) {
|
||||||
default: RCTStatusBarManager.Style.default,
|
|
||||||
lightContent: RCTStatusBarManager.Style.lightContent
|
|
||||||
},
|
|
||||||
|
|
||||||
Animation: {
|
|
||||||
none: RCTStatusBarManager.Animation.none,
|
|
||||||
fade: RCTStatusBarManager.Animation.fade,
|
|
||||||
slide: RCTStatusBarManager.Animation.slide,
|
|
||||||
},
|
|
||||||
|
|
||||||
setStyle(style: number, animated?: boolean) {
|
|
||||||
animated = animated || false;
|
animated = animated || false;
|
||||||
RCTStatusBarManager.setStyle(style, animated);
|
RCTStatusBarManager.setStyle(style, animated);
|
||||||
},
|
},
|
||||||
|
|
||||||
setHidden(hidden: boolean, animation: number) {
|
setHidden(hidden: boolean, animation?: StatusBarAnimation) {
|
||||||
animation = animation || StatusBarIOS.Animation.none;
|
animation = animation || 'none';
|
||||||
RCTStatusBarManager.setHidden(hidden, animation);
|
RCTStatusBarManager.setHidden(hidden, animation);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -31,10 +31,6 @@ var emptyFunction = require('emptyFunction');
|
|||||||
var invariant = require('invariant');
|
var invariant = require('invariant');
|
||||||
var merge = require('merge');
|
var merge = require('merge');
|
||||||
|
|
||||||
var autoCapitalizeConsts = RCTUIManager.UIText.AutocapitalizationType;
|
|
||||||
var keyboardTypeConsts = RCTUIManager.UIKeyboardType;
|
|
||||||
var returnKeyTypeConsts = RCTUIManager.UIReturnKeyType;
|
|
||||||
|
|
||||||
var RCTTextViewAttributes = merge(ReactNativeViewAttributes.UIView, {
|
var RCTTextViewAttributes = merge(ReactNativeViewAttributes.UIView, {
|
||||||
autoCorrect: true,
|
autoCorrect: true,
|
||||||
autoCapitalize: true,
|
autoCapitalize: true,
|
||||||
@ -96,10 +92,6 @@ var viewConfigAndroid = {
|
|||||||
validAttributes: AndroidTextInputAttributes,
|
validAttributes: AndroidTextInputAttributes,
|
||||||
};
|
};
|
||||||
|
|
||||||
var crossPlatformKeyboardTypeMap = {
|
|
||||||
'numeric': 'decimal-pad',
|
|
||||||
};
|
|
||||||
|
|
||||||
type DefaultProps = {
|
type DefaultProps = {
|
||||||
bufferDelay: number;
|
bufferDelay: number;
|
||||||
};
|
};
|
||||||
@ -171,8 +163,11 @@ var TextInput = React.createClass({
|
|||||||
* Determines which keyboard to open, e.g.`numeric`.
|
* Determines which keyboard to open, e.g.`numeric`.
|
||||||
*/
|
*/
|
||||||
keyboardType: PropTypes.oneOf([
|
keyboardType: PropTypes.oneOf([
|
||||||
|
// Cross-platform
|
||||||
'default',
|
'default',
|
||||||
// iOS
|
'numeric',
|
||||||
|
'email-address',
|
||||||
|
// iOS-only
|
||||||
'ascii-capable',
|
'ascii-capable',
|
||||||
'numbers-and-punctuation',
|
'numbers-and-punctuation',
|
||||||
'url',
|
'url',
|
||||||
@ -182,9 +177,6 @@ var TextInput = React.createClass({
|
|||||||
'decimal-pad',
|
'decimal-pad',
|
||||||
'twitter',
|
'twitter',
|
||||||
'web-search',
|
'web-search',
|
||||||
// Cross-platform
|
|
||||||
'numeric',
|
|
||||||
'email-address',
|
|
||||||
]),
|
]),
|
||||||
/**
|
/**
|
||||||
* Determines how the return key should look.
|
* Determines how the return key should look.
|
||||||
@ -426,18 +418,12 @@ var TextInput = React.createClass({
|
|||||||
_renderIOS: function() {
|
_renderIOS: function() {
|
||||||
var textContainer;
|
var textContainer;
|
||||||
|
|
||||||
var autoCapitalize = autoCapitalizeConsts[this.props.autoCapitalize];
|
var props = this.props;
|
||||||
var clearButtonMode = RCTUIManager.UITextField.clearButtonMode[this.props.clearButtonMode];
|
props.style = [styles.input, this.props.style];
|
||||||
|
|
||||||
var keyboardType = keyboardTypeConsts[
|
if (!props.multiline) {
|
||||||
crossPlatformKeyboardTypeMap[this.props.keyboardType] ||
|
|
||||||
this.props.keyboardType
|
|
||||||
];
|
|
||||||
var returnKeyType = returnKeyTypeConsts[this.props.returnKeyType];
|
|
||||||
|
|
||||||
if (!this.props.multiline) {
|
|
||||||
for (var propKey in onlyMultiline) {
|
for (var propKey in onlyMultiline) {
|
||||||
if (this.props[propKey]) {
|
if (props[propKey]) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
'TextInput prop `' + propKey + '` is only supported with multiline.'
|
'TextInput prop `' + propKey + '` is only supported with multiline.'
|
||||||
);
|
);
|
||||||
@ -446,77 +432,48 @@ var TextInput = React.createClass({
|
|||||||
textContainer =
|
textContainer =
|
||||||
<RCTTextField
|
<RCTTextField
|
||||||
ref="input"
|
ref="input"
|
||||||
style={[styles.input, this.props.style]}
|
{...props}
|
||||||
enabled={this.props.editable}
|
|
||||||
keyboardType={keyboardType}
|
|
||||||
returnKeyType={returnKeyType}
|
|
||||||
enablesReturnKeyAutomatically={this.props.enablesReturnKeyAutomatically}
|
|
||||||
secureTextEntry={this.props.password || this.props.secureTextEntry}
|
|
||||||
onFocus={this._onFocus}
|
onFocus={this._onFocus}
|
||||||
onBlur={this._onBlur}
|
onBlur={this._onBlur}
|
||||||
onChange={this._onChange}
|
onChange={this._onChange}
|
||||||
onEndEditing={this.props.onEndEditing}
|
|
||||||
onSubmitEditing={this.props.onSubmitEditing}
|
|
||||||
onSelectionChangeShouldSetResponder={() => true}
|
onSelectionChangeShouldSetResponder={() => true}
|
||||||
onLayout={this.props.onLayout}
|
|
||||||
placeholder={this.props.placeholder}
|
|
||||||
placeholderTextColor={this.props.placeholderTextColor}
|
|
||||||
text={this.state.bufferedValue}
|
text={this.state.bufferedValue}
|
||||||
autoCapitalize={autoCapitalize}
|
|
||||||
autoCorrect={this.props.autoCorrect}
|
|
||||||
clearButtonMode={clearButtonMode}
|
|
||||||
clearTextOnFocus={this.props.clearTextOnFocus}
|
|
||||||
selectTextOnFocus={this.props.selectTextOnFocus}
|
|
||||||
/>;
|
/>;
|
||||||
} else {
|
} else {
|
||||||
for (var propKey in notMultiline) {
|
for (var propKey in notMultiline) {
|
||||||
if (this.props[propKey]) {
|
if (props[propKey]) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
'TextInput prop `' + propKey + '` cannot be used with multiline.'
|
'TextInput prop `' + propKey + '` cannot be used with multiline.'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var children = this.props.children;
|
var children = props.children;
|
||||||
var childCount = 0;
|
var childCount = 0;
|
||||||
ReactChildren.forEach(children, () => ++childCount);
|
ReactChildren.forEach(children, () => ++childCount);
|
||||||
invariant(
|
invariant(
|
||||||
!(this.props.value && childCount),
|
!(props.value && childCount),
|
||||||
'Cannot specify both value and children.'
|
'Cannot specify both value and children.'
|
||||||
);
|
);
|
||||||
if (childCount > 1) {
|
if (childCount > 1) {
|
||||||
children = <Text>{children}</Text>;
|
children = <Text>{children}</Text>;
|
||||||
}
|
}
|
||||||
if (this.props.inputView) {
|
if (props.inputView) {
|
||||||
children = [children, this.props.inputView];
|
children = [children, props.inputView];
|
||||||
}
|
}
|
||||||
textContainer =
|
textContainer =
|
||||||
<RCTTextView
|
<RCTTextView
|
||||||
ref="input"
|
ref="input"
|
||||||
style={[styles.input, this.props.style]}
|
{...props}
|
||||||
children={children}
|
children={children}
|
||||||
mostRecentEventCounter={this.state.mostRecentEventCounter}
|
mostRecentEventCounter={this.state.mostRecentEventCounter}
|
||||||
editable={this.props.editable}
|
|
||||||
keyboardType={keyboardType}
|
|
||||||
returnKeyType={returnKeyType}
|
|
||||||
enablesReturnKeyAutomatically={this.props.enablesReturnKeyAutomatically}
|
|
||||||
secureTextEntry={this.props.password || this.props.secureTextEntry}
|
|
||||||
onFocus={this._onFocus}
|
onFocus={this._onFocus}
|
||||||
onBlur={this._onBlur}
|
onBlur={this._onBlur}
|
||||||
onChange={this._onChange}
|
onChange={this._onChange}
|
||||||
onEndEditing={this.props.onEndEditing}
|
|
||||||
onSelectionChange={this._onSelectionChange}
|
onSelectionChange={this._onSelectionChange}
|
||||||
onTextInput={this._onTextInput}
|
onTextInput={this._onTextInput}
|
||||||
onSelectionChangeShouldSetResponder={emptyFunction.thatReturnsTrue}
|
onSelectionChangeShouldSetResponder={emptyFunction.thatReturnsTrue}
|
||||||
onLayout={this.props.onLayout}
|
|
||||||
placeholder={this.props.placeholder}
|
|
||||||
placeholderTextColor={this.props.placeholderTextColor}
|
|
||||||
text={this.state.bufferedValue}
|
text={this.state.bufferedValue}
|
||||||
autoCapitalize={autoCapitalize}
|
|
||||||
autoCorrect={this.props.autoCorrect}
|
|
||||||
clearButtonMode={clearButtonMode}
|
|
||||||
selectTextOnFocus={this.props.selectTextOnFocus}
|
|
||||||
clearTextOnFocus={this.props.clearTextOnFocus}
|
|
||||||
/>;
|
/>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -524,14 +481,14 @@ var TextInput = React.createClass({
|
|||||||
<TouchableWithoutFeedback
|
<TouchableWithoutFeedback
|
||||||
onPress={this._onPress}
|
onPress={this._onPress}
|
||||||
rejectResponderTermination={true}
|
rejectResponderTermination={true}
|
||||||
testID={this.props.testID}>
|
testID={props.testID}>
|
||||||
{textContainer}
|
{textContainer}
|
||||||
</TouchableWithoutFeedback>
|
</TouchableWithoutFeedback>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
_renderAndroid: function() {
|
_renderAndroid: function() {
|
||||||
var autoCapitalize = autoCapitalizeConsts[this.props.autoCapitalize];
|
var autoCapitalize = RCTUIManager.UIText.AutocapitalizationType[this.props.autoCapitalize];
|
||||||
var children = this.props.children;
|
var children = this.props.children;
|
||||||
var childCount = 0;
|
var childCount = 0;
|
||||||
ReactChildren.forEach(children, () => ++childCount);
|
ReactChildren.forEach(children, () => ++childCount);
|
||||||
|
@ -23,6 +23,7 @@ var View = require('View');
|
|||||||
|
|
||||||
var cloneWithProps = require('cloneWithProps');
|
var cloneWithProps = require('cloneWithProps');
|
||||||
var ensureComponentIsNative = require('ensureComponentIsNative');
|
var ensureComponentIsNative = require('ensureComponentIsNative');
|
||||||
|
var ensurePositiveDelayProps = require('ensurePositiveDelayProps');
|
||||||
var keyOf = require('keyOf');
|
var keyOf = require('keyOf');
|
||||||
var merge = require('merge');
|
var merge = require('merge');
|
||||||
var onlyChild = require('onlyChild');
|
var onlyChild = require('onlyChild');
|
||||||
@ -111,6 +112,7 @@ var TouchableHighlight = React.createClass({
|
|||||||
},
|
},
|
||||||
|
|
||||||
componentDidMount: function() {
|
componentDidMount: function() {
|
||||||
|
ensurePositiveDelayProps(this.props);
|
||||||
ensureComponentIsNative(this.refs[CHILD_REF]);
|
ensureComponentIsNative(this.refs[CHILD_REF]);
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -119,6 +121,7 @@ var TouchableHighlight = React.createClass({
|
|||||||
},
|
},
|
||||||
|
|
||||||
componentWillReceiveProps: function(nextProps) {
|
componentWillReceiveProps: function(nextProps) {
|
||||||
|
ensurePositiveDelayProps(nextProps);
|
||||||
if (nextProps.activeOpacity !== this.props.activeOpacity ||
|
if (nextProps.activeOpacity !== this.props.activeOpacity ||
|
||||||
nextProps.underlayColor !== this.props.underlayColor ||
|
nextProps.underlayColor !== this.props.underlayColor ||
|
||||||
nextProps.style !== this.props.style) {
|
nextProps.style !== this.props.style) {
|
||||||
@ -152,7 +155,8 @@ var TouchableHighlight = React.createClass({
|
|||||||
touchableHandlePress: function() {
|
touchableHandlePress: function() {
|
||||||
this.clearTimeout(this._hideTimeout);
|
this.clearTimeout(this._hideTimeout);
|
||||||
this._showUnderlay();
|
this._showUnderlay();
|
||||||
this._hideTimeout = this.setTimeout(this._hideUnderlay, 100);
|
this._hideTimeout = this.setTimeout(this._hideUnderlay,
|
||||||
|
this.props.delayPressOut || 100);
|
||||||
this.props.onPress && this.props.onPress();
|
this.props.onPress && this.props.onPress();
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -164,6 +168,18 @@ var TouchableHighlight = React.createClass({
|
|||||||
return PRESS_RECT_OFFSET; // Always make sure to predeclare a constant!
|
return PRESS_RECT_OFFSET; // Always make sure to predeclare a constant!
|
||||||
},
|
},
|
||||||
|
|
||||||
|
touchableGetHighlightDelayMS: function() {
|
||||||
|
return this.props.delayPressIn;
|
||||||
|
},
|
||||||
|
|
||||||
|
touchableGetLongPressDelayMS: function() {
|
||||||
|
return this.props.delayLongPress;
|
||||||
|
},
|
||||||
|
|
||||||
|
touchableGetPressOutDelayMS: function() {
|
||||||
|
return this.props.delayPressOut;
|
||||||
|
},
|
||||||
|
|
||||||
_showUnderlay: function() {
|
_showUnderlay: function() {
|
||||||
this.refs[UNDERLAY_REF].setNativeProps(this.state.activeUnderlayProps);
|
this.refs[UNDERLAY_REF].setNativeProps(this.state.activeUnderlayProps);
|
||||||
this.refs[CHILD_REF].setNativeProps(this.state.activeProps);
|
this.refs[CHILD_REF].setNativeProps(this.state.activeProps);
|
||||||
|
@ -15,11 +15,13 @@
|
|||||||
var NativeMethodsMixin = require('NativeMethodsMixin');
|
var NativeMethodsMixin = require('NativeMethodsMixin');
|
||||||
var POPAnimationMixin = require('POPAnimationMixin');
|
var POPAnimationMixin = require('POPAnimationMixin');
|
||||||
var React = require('React');
|
var React = require('React');
|
||||||
|
var TimerMixin = require('react-timer-mixin');
|
||||||
var Touchable = require('Touchable');
|
var Touchable = require('Touchable');
|
||||||
var TouchableWithoutFeedback = require('TouchableWithoutFeedback');
|
var TouchableWithoutFeedback = require('TouchableWithoutFeedback');
|
||||||
|
|
||||||
var cloneWithProps = require('cloneWithProps');
|
var cloneWithProps = require('cloneWithProps');
|
||||||
var ensureComponentIsNative = require('ensureComponentIsNative');
|
var ensureComponentIsNative = require('ensureComponentIsNative');
|
||||||
|
var ensurePositiveDelayProps = require('ensurePositiveDelayProps');
|
||||||
var flattenStyle = require('flattenStyle');
|
var flattenStyle = require('flattenStyle');
|
||||||
var keyOf = require('keyOf');
|
var keyOf = require('keyOf');
|
||||||
var onlyChild = require('onlyChild');
|
var onlyChild = require('onlyChild');
|
||||||
@ -50,7 +52,7 @@ var onlyChild = require('onlyChild');
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
var TouchableOpacity = React.createClass({
|
var TouchableOpacity = React.createClass({
|
||||||
mixins: [Touchable.Mixin, NativeMethodsMixin, POPAnimationMixin],
|
mixins: [TimerMixin, Touchable.Mixin, NativeMethodsMixin, POPAnimationMixin],
|
||||||
|
|
||||||
propTypes: {
|
propTypes: {
|
||||||
...TouchableWithoutFeedback.propTypes,
|
...TouchableWithoutFeedback.propTypes,
|
||||||
@ -72,6 +74,7 @@ var TouchableOpacity = React.createClass({
|
|||||||
},
|
},
|
||||||
|
|
||||||
componentDidMount: function() {
|
componentDidMount: function() {
|
||||||
|
ensurePositiveDelayProps(this.props);
|
||||||
ensureComponentIsNative(this.refs[CHILD_REF]);
|
ensureComponentIsNative(this.refs[CHILD_REF]);
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -79,6 +82,10 @@ var TouchableOpacity = React.createClass({
|
|||||||
ensureComponentIsNative(this.refs[CHILD_REF]);
|
ensureComponentIsNative(this.refs[CHILD_REF]);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
componentWillReceiveProps: function(nextProps) {
|
||||||
|
ensurePositiveDelayProps(nextProps);
|
||||||
|
},
|
||||||
|
|
||||||
setOpacityTo: function(value) {
|
setOpacityTo: function(value) {
|
||||||
if (POPAnimationMixin) {
|
if (POPAnimationMixin) {
|
||||||
// Reset with animation if POP is available
|
// Reset with animation if POP is available
|
||||||
@ -86,6 +93,7 @@ var TouchableOpacity = React.createClass({
|
|||||||
var anim = {
|
var anim = {
|
||||||
type: this.AnimationTypes.linear,
|
type: this.AnimationTypes.linear,
|
||||||
property: this.AnimationProperties.opacity,
|
property: this.AnimationProperties.opacity,
|
||||||
|
duration: 0.15,
|
||||||
toValue: value,
|
toValue: value,
|
||||||
};
|
};
|
||||||
this.startAnimation(CHILD_REF, anim);
|
this.startAnimation(CHILD_REF, anim);
|
||||||
@ -102,20 +110,26 @@ var TouchableOpacity = React.createClass({
|
|||||||
* defined on your component.
|
* defined on your component.
|
||||||
*/
|
*/
|
||||||
touchableHandleActivePressIn: function() {
|
touchableHandleActivePressIn: function() {
|
||||||
this.refs[CHILD_REF].setNativeProps({
|
this.clearTimeout(this._hideTimeout);
|
||||||
opacity: this.props.activeOpacity
|
this._hideTimeout = null;
|
||||||
});
|
this._opacityActive();
|
||||||
this.props.onPressIn && this.props.onPressIn();
|
this.props.onPressIn && this.props.onPressIn();
|
||||||
},
|
},
|
||||||
|
|
||||||
touchableHandleActivePressOut: function() {
|
touchableHandleActivePressOut: function() {
|
||||||
var child = onlyChild(this.props.children);
|
if (!this._hideTimeout) {
|
||||||
var childStyle = flattenStyle(child.props.style) || {};
|
this._opacityInactive();
|
||||||
this.setOpacityTo(childStyle.opacity === undefined ? 1 : childStyle.opacity);
|
}
|
||||||
this.props.onPressOut && this.props.onPressOut();
|
this.props.onPressOut && this.props.onPressOut();
|
||||||
},
|
},
|
||||||
|
|
||||||
touchableHandlePress: function() {
|
touchableHandlePress: function() {
|
||||||
|
this.clearTimeout(this._hideTimeout);
|
||||||
|
this._opacityActive();
|
||||||
|
this._hideTimeout = this.setTimeout(
|
||||||
|
this._opacityInactive,
|
||||||
|
this.props.delayPressOut || 100
|
||||||
|
);
|
||||||
this.props.onPress && this.props.onPress();
|
this.props.onPress && this.props.onPress();
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -128,7 +142,30 @@ var TouchableOpacity = React.createClass({
|
|||||||
},
|
},
|
||||||
|
|
||||||
touchableGetHighlightDelayMS: function() {
|
touchableGetHighlightDelayMS: function() {
|
||||||
return 0;
|
return this.props.delayPressIn || 0;
|
||||||
|
},
|
||||||
|
|
||||||
|
touchableGetLongPressDelayMS: function() {
|
||||||
|
return this.props.delayLongPress === 0 ? 0 :
|
||||||
|
this.props.delayLongPress || 500;
|
||||||
|
},
|
||||||
|
|
||||||
|
touchableGetPressOutDelayMS: function() {
|
||||||
|
return this.props.delayPressOut;
|
||||||
|
},
|
||||||
|
|
||||||
|
_opacityActive: function() {
|
||||||
|
this.setOpacityTo(this.props.activeOpacity);
|
||||||
|
},
|
||||||
|
|
||||||
|
_opacityInactive: function() {
|
||||||
|
this.clearTimeout(this._hideTimeout);
|
||||||
|
this._hideTimeout = null;
|
||||||
|
var child = onlyChild(this.props.children);
|
||||||
|
var childStyle = flattenStyle(child.props.style) || {};
|
||||||
|
this.setOpacityTo(
|
||||||
|
childStyle.opacity === undefined ? 1 : childStyle.opacity
|
||||||
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
render: function() {
|
render: function() {
|
||||||
|
@ -12,7 +12,9 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var React = require('React');
|
var React = require('React');
|
||||||
|
var TimerMixin = require('react-timer-mixin');
|
||||||
var Touchable = require('Touchable');
|
var Touchable = require('Touchable');
|
||||||
|
var ensurePositiveDelayProps = require('ensurePositiveDelayProps');
|
||||||
var onlyChild = require('onlyChild');
|
var onlyChild = require('onlyChild');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -31,23 +33,44 @@ type Event = Object;
|
|||||||
* one of the primary reason a "web" app doesn't feel "native".
|
* one of the primary reason a "web" app doesn't feel "native".
|
||||||
*/
|
*/
|
||||||
var TouchableWithoutFeedback = React.createClass({
|
var TouchableWithoutFeedback = React.createClass({
|
||||||
mixins: [Touchable.Mixin],
|
mixins: [TimerMixin, Touchable.Mixin],
|
||||||
|
|
||||||
propTypes: {
|
propTypes: {
|
||||||
/**
|
/**
|
||||||
* Called when the touch is released, but not if cancelled (e.g. by a scroll
|
* Called when the touch is released, but not if cancelled (e.g. by a scroll
|
||||||
* that steals the responder lock).
|
* that steals the responder lock).
|
||||||
*/
|
*/
|
||||||
|
accessible: React.PropTypes.bool,
|
||||||
onPress: React.PropTypes.func,
|
onPress: React.PropTypes.func,
|
||||||
onPressIn: React.PropTypes.func,
|
onPressIn: React.PropTypes.func,
|
||||||
onPressOut: React.PropTypes.func,
|
onPressOut: React.PropTypes.func,
|
||||||
onLongPress: React.PropTypes.func,
|
onLongPress: React.PropTypes.func,
|
||||||
|
/**
|
||||||
|
* Delay in ms, from the start of the touch, before onPressIn is called.
|
||||||
|
*/
|
||||||
|
delayPressIn: React.PropTypes.number,
|
||||||
|
/**
|
||||||
|
* Delay in ms, from the release of the touch, before onPressOut is called.
|
||||||
|
*/
|
||||||
|
delayPressOut: React.PropTypes.number,
|
||||||
|
/**
|
||||||
|
* Delay in ms, from onPressIn, before onLongPress is called.
|
||||||
|
*/
|
||||||
|
delayLongPress: React.PropTypes.number,
|
||||||
},
|
},
|
||||||
|
|
||||||
getInitialState: function() {
|
getInitialState: function() {
|
||||||
return this.touchableGetInitialState();
|
return this.touchableGetInitialState();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
componentDidMount: function() {
|
||||||
|
ensurePositiveDelayProps(this.props);
|
||||||
|
},
|
||||||
|
|
||||||
|
componentWillReceiveProps: function(nextProps: Object) {
|
||||||
|
ensurePositiveDelayProps(nextProps);
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* `Touchable.Mixin` self callbacks. The mixin will invoke these if they are
|
* `Touchable.Mixin` self callbacks. The mixin will invoke these if they are
|
||||||
* defined on your component.
|
* defined on your component.
|
||||||
@ -73,13 +96,22 @@ var TouchableWithoutFeedback = React.createClass({
|
|||||||
},
|
},
|
||||||
|
|
||||||
touchableGetHighlightDelayMS: function(): number {
|
touchableGetHighlightDelayMS: function(): number {
|
||||||
return 0;
|
return this.props.delayPressIn || 0;
|
||||||
|
},
|
||||||
|
|
||||||
|
touchableGetLongPressDelayMS: function(): number {
|
||||||
|
return this.props.delayLongPress === 0 ? 0 :
|
||||||
|
this.props.delayLongPress || 500;
|
||||||
|
},
|
||||||
|
|
||||||
|
touchableGetPressOutDelayMS: function(): number {
|
||||||
|
return this.props.delayPressOut || 0;
|
||||||
},
|
},
|
||||||
|
|
||||||
render: function(): ReactElement {
|
render: function(): ReactElement {
|
||||||
// Note(avik): remove dynamic typecast once Flow has been upgraded
|
// Note(avik): remove dynamic typecast once Flow has been upgraded
|
||||||
return (React: any).cloneElement(onlyChild(this.props.children), {
|
return (React: any).cloneElement(onlyChild(this.props.children), {
|
||||||
accessible: true,
|
accessible: this.props.accessible !== false,
|
||||||
testID: this.props.testID,
|
testID: this.props.testID,
|
||||||
onStartShouldSetResponder: this.touchableHandleStartShouldSetResponder,
|
onStartShouldSetResponder: this.touchableHandleStartShouldSetResponder,
|
||||||
onResponderTerminationRequest: this.touchableHandleResponderTerminationRequest,
|
onResponderTerminationRequest: this.touchableHandleResponderTerminationRequest,
|
||||||
|
24
Libraries/Components/Touchable/ensurePositiveDelayProps.js
Normal file
24
Libraries/Components/Touchable/ensurePositiveDelayProps.js
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
/**
|
||||||
|
* 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 ensurePositiveDelayProps
|
||||||
|
* @flow
|
||||||
|
*/
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var invariant = require('invariant');
|
||||||
|
|
||||||
|
var ensurePositiveDelayProps = function(props: any) {
|
||||||
|
invariant(
|
||||||
|
!(props.delayPressIn < 0 || props.delayPressOut < 0 ||
|
||||||
|
props.delayLongPress < 0),
|
||||||
|
'Touchable components cannot have negative delay properties'
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = ensurePositiveDelayProps;
|
@ -146,20 +146,11 @@ var Image = React.createClass({
|
|||||||
if (this.props.style && this.props.style.tintColor) {
|
if (this.props.style && this.props.style.tintColor) {
|
||||||
warning(RawImage === RCTStaticImage, 'tintColor style only supported on static images.');
|
warning(RawImage === RCTStaticImage, 'tintColor style only supported on static images.');
|
||||||
}
|
}
|
||||||
var resizeMode = this.props.resizeMode || style.resizeMode;
|
var resizeMode = this.props.resizeMode || style.resizeMode || 'cover';
|
||||||
var contentModes = NativeModules.UIManager.UIView.ContentMode;
|
|
||||||
var contentMode;
|
|
||||||
if (resizeMode === ImageResizeMode.stretch) {
|
|
||||||
contentMode = contentModes.ScaleToFill;
|
|
||||||
} else if (resizeMode === ImageResizeMode.contain) {
|
|
||||||
contentMode = contentModes.ScaleAspectFit;
|
|
||||||
} else { // ImageResizeMode.cover or undefined
|
|
||||||
contentMode = contentModes.ScaleAspectFill;
|
|
||||||
}
|
|
||||||
|
|
||||||
var nativeProps = merge(this.props, {
|
var nativeProps = merge(this.props, {
|
||||||
style,
|
style,
|
||||||
contentMode,
|
resizeMode,
|
||||||
tintColor: style.tintColor,
|
tintColor: style.tintColor,
|
||||||
});
|
});
|
||||||
if (isStored) {
|
if (isStored) {
|
||||||
@ -187,7 +178,7 @@ var nativeOnlyProps = {
|
|||||||
src: true,
|
src: true,
|
||||||
defaultImageSrc: true,
|
defaultImageSrc: true,
|
||||||
imageTag: true,
|
imageTag: true,
|
||||||
contentMode: true,
|
resizeMode: true,
|
||||||
};
|
};
|
||||||
if (__DEV__) {
|
if (__DEV__) {
|
||||||
verifyPropTypes(Image, RCTStaticImage.viewConfig, nativeOnlyProps);
|
verifyPropTypes(Image, RCTStaticImage.viewConfig, nativeOnlyProps);
|
||||||
|
@ -82,8 +82,8 @@ static NSString *RCTCacheKeyForURL(NSURL *url)
|
|||||||
RCTImageDownloader *strongSelf = weakSelf;
|
RCTImageDownloader *strongSelf = weakSelf;
|
||||||
NSArray *blocks = strongSelf->_pendingBlocks[cacheKey];
|
NSArray *blocks = strongSelf->_pendingBlocks[cacheKey];
|
||||||
[strongSelf->_pendingBlocks removeObjectForKey:cacheKey];
|
[strongSelf->_pendingBlocks removeObjectForKey:cacheKey];
|
||||||
for (RCTCachedDataDownloadBlock block in blocks) {
|
for (RCTCachedDataDownloadBlock cacheDownloadBlock in blocks) {
|
||||||
block(cached, data, error);
|
cacheDownloadBlock(cached, data, error);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -29,6 +29,6 @@ RCT_EXPORT_MODULE()
|
|||||||
|
|
||||||
RCT_REMAP_VIEW_PROPERTY(defaultImageSrc, defaultImage, UIImage)
|
RCT_REMAP_VIEW_PROPERTY(defaultImageSrc, defaultImage, UIImage)
|
||||||
RCT_REMAP_VIEW_PROPERTY(src, imageURL, NSURL)
|
RCT_REMAP_VIEW_PROPERTY(src, imageURL, NSURL)
|
||||||
RCT_EXPORT_VIEW_PROPERTY(contentMode, UIViewContentMode)
|
RCT_REMAP_VIEW_PROPERTY(resizeMode, contentMode, UIViewContentMode)
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
@ -26,7 +26,7 @@ RCT_EXPORT_MODULE()
|
|||||||
}
|
}
|
||||||
|
|
||||||
RCT_EXPORT_VIEW_PROPERTY(capInsets, UIEdgeInsets)
|
RCT_EXPORT_VIEW_PROPERTY(capInsets, UIEdgeInsets)
|
||||||
RCT_EXPORT_VIEW_PROPERTY(contentMode, UIViewContentMode)
|
RCT_REMAP_VIEW_PROPERTY(resizeMode, contentMode, UIViewContentMode)
|
||||||
RCT_CUSTOM_VIEW_PROPERTY(src, NSURL, RCTStaticImage)
|
RCT_CUSTOM_VIEW_PROPERTY(src, NSURL, RCTStaticImage)
|
||||||
{
|
{
|
||||||
if (json) {
|
if (json) {
|
||||||
|
@ -50,6 +50,9 @@ function findInstanceByNativeTag(rootTag, nativeTag) {
|
|||||||
var containerID = ReactNativeTagHandles.tagToRootNodeID[rootTag];
|
var containerID = ReactNativeTagHandles.tagToRootNodeID[rootTag];
|
||||||
var rootInstance = ReactNativeMount._instancesByContainerID[containerID];
|
var rootInstance = ReactNativeMount._instancesByContainerID[containerID];
|
||||||
var targetID = ReactNativeTagHandles.tagToRootNodeID[nativeTag];
|
var targetID = ReactNativeTagHandles.tagToRootNodeID[nativeTag];
|
||||||
|
if (!targetID) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
return findInstance(rootInstance, targetID);
|
return findInstance(rootInstance, targetID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,8 +20,7 @@ var RCTPickerIOSConsts = require('NativeModules').UIManager.RCTPicker.Constants;
|
|||||||
var StyleSheet = require('StyleSheet');
|
var StyleSheet = require('StyleSheet');
|
||||||
var View = require('View');
|
var View = require('View');
|
||||||
|
|
||||||
var createReactNativeComponentClass =
|
var requireNativeComponent = require('requireNativeComponent');
|
||||||
require('createReactNativeComponentClass');
|
|
||||||
var merge = require('merge');
|
var merge = require('merge');
|
||||||
|
|
||||||
var PICKER = 'picker';
|
var PICKER = 'picker';
|
||||||
@ -60,7 +59,7 @@ var PickerIOS = React.createClass({
|
|||||||
<View style={this.props.style}>
|
<View style={this.props.style}>
|
||||||
<RCTPickerIOS
|
<RCTPickerIOS
|
||||||
ref={PICKER}
|
ref={PICKER}
|
||||||
style={styles.rkPickerIOS}
|
style={styles.pickerIOS}
|
||||||
items={this.state.items}
|
items={this.state.items}
|
||||||
selectedIndex={this.state.selectedIndex}
|
selectedIndex={this.state.selectedIndex}
|
||||||
onChange={this._onChange}
|
onChange={this._onChange}
|
||||||
@ -104,7 +103,7 @@ PickerIOS.Item = React.createClass({
|
|||||||
});
|
});
|
||||||
|
|
||||||
var styles = StyleSheet.create({
|
var styles = StyleSheet.create({
|
||||||
rkPickerIOS: {
|
pickerIOS: {
|
||||||
// The picker will conform to whatever width is given, but we do
|
// The picker will conform to whatever width is given, but we do
|
||||||
// have to set the component's height explicitly on the
|
// have to set the component's height explicitly on the
|
||||||
// surrounding view to ensure it gets rendered.
|
// surrounding view to ensure it gets rendered.
|
||||||
@ -112,14 +111,6 @@ var styles = StyleSheet.create({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
var rkPickerIOSAttributes = merge(ReactNativeViewAttributes.UIView, {
|
var RCTPickerIOS = requireNativeComponent('RCTPicker', null);
|
||||||
items: true,
|
|
||||||
selectedIndex: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
var RCTPickerIOS = createReactNativeComponentClass({
|
|
||||||
validAttributes: rkPickerIOSAttributes,
|
|
||||||
uiViewClassName: 'RCTPicker',
|
|
||||||
});
|
|
||||||
|
|
||||||
module.exports = PickerIOS;
|
module.exports = PickerIOS;
|
||||||
|
@ -20,6 +20,7 @@ var _initialNotification = RCTPushNotificationManager &&
|
|||||||
RCTPushNotificationManager.initialNotification;
|
RCTPushNotificationManager.initialNotification;
|
||||||
|
|
||||||
var DEVICE_NOTIF_EVENT = 'remoteNotificationReceived';
|
var DEVICE_NOTIF_EVENT = 'remoteNotificationReceived';
|
||||||
|
var NOTIF_REGISTER_EVENT = 'remoteNotificationsRegistered';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle push notifications for your app, including permission handling and
|
* Handle push notifications for your app, including permission handling and
|
||||||
@ -49,30 +50,72 @@ class PushNotificationIOS {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attaches a listener to remote notifications while the app is running in the
|
* Attaches a listener to remote notification events while the app is running
|
||||||
* foreground or the background.
|
* in the foreground or the background.
|
||||||
*
|
*
|
||||||
* The handler will get be invoked with an instance of `PushNotificationIOS`
|
* Valid events are:
|
||||||
|
*
|
||||||
|
* - `notification` : Fired when a remote notification is received. The
|
||||||
|
* handler will be invoked with an instance of `PushNotificationIOS`.
|
||||||
|
* - `register`: Fired when the user registers for remote notifications. The
|
||||||
|
* handler will be invoked with a hex string representing the deviceToken.
|
||||||
*/
|
*/
|
||||||
static addEventListener(type: string, handler: Function) {
|
static addEventListener(type: string, handler: Function) {
|
||||||
invariant(
|
invariant(
|
||||||
type === 'notification',
|
type === 'notification' || type === 'register',
|
||||||
'PushNotificationIOS only supports `notification` events'
|
'PushNotificationIOS only supports `notification` and `register` events'
|
||||||
);
|
);
|
||||||
|
if (type === 'notification') {
|
||||||
_notifHandlers[handler] = RCTDeviceEventEmitter.addListener(
|
_notifHandlers[handler] = RCTDeviceEventEmitter.addListener(
|
||||||
DEVICE_NOTIF_EVENT,
|
DEVICE_NOTIF_EVENT,
|
||||||
(notifData) => {
|
(notifData) => {
|
||||||
handler(new PushNotificationIOS(notifData));
|
handler(new PushNotificationIOS(notifData));
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
} else if (type === 'register') {
|
||||||
|
_notifHandlers[handler] = RCTDeviceEventEmitter.addListener(
|
||||||
|
NOTIF_REGISTER_EVENT,
|
||||||
|
(registrationInfo) => {
|
||||||
|
handler(registrationInfo.deviceToken);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Requests all notification permissions from iOS, prompting the user's
|
* Requests notification permissions from iOS, prompting the user's
|
||||||
* dialog box.
|
* dialog box. By default, it will request all notification permissions, but
|
||||||
|
* a subset of these can be requested by passing a map of requested
|
||||||
|
* permissions.
|
||||||
|
* The following permissions are supported:
|
||||||
|
*
|
||||||
|
* - `alert`
|
||||||
|
* - `badge`
|
||||||
|
* - `sound`
|
||||||
|
*
|
||||||
|
* If a map is provided to the method, only the permissions with truthy values
|
||||||
|
* will be requested.
|
||||||
*/
|
*/
|
||||||
static requestPermissions() {
|
static requestPermissions(permissions?: {
|
||||||
RCTPushNotificationManager.requestPermissions();
|
alert?: boolean,
|
||||||
|
badge?: boolean,
|
||||||
|
sound?: boolean
|
||||||
|
}) {
|
||||||
|
var requestedPermissions = {};
|
||||||
|
if (permissions) {
|
||||||
|
requestedPermissions = {
|
||||||
|
alert: !!permissions.alert,
|
||||||
|
badge: !!permissions.badge,
|
||||||
|
sound: !!permissions.sound
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
requestedPermissions = {
|
||||||
|
alert: true,
|
||||||
|
badge: true,
|
||||||
|
sound: true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
RCTPushNotificationManager.requestPermissions(requestedPermissions);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -97,8 +140,8 @@ class PushNotificationIOS {
|
|||||||
*/
|
*/
|
||||||
static removeEventListener(type: string, handler: Function) {
|
static removeEventListener(type: string, handler: Function) {
|
||||||
invariant(
|
invariant(
|
||||||
type === 'notification',
|
type === 'notification' || type === 'register',
|
||||||
'PushNotificationIOS only supports `notification` events'
|
'PushNotificationIOS only supports `notification` and `register` events'
|
||||||
);
|
);
|
||||||
if (!_notifHandlers[handler]) {
|
if (!_notifHandlers[handler]) {
|
||||||
return;
|
return;
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
@interface RCTPushNotificationManager : NSObject <RCTBridgeModule>
|
@interface RCTPushNotificationManager : NSObject <RCTBridgeModule>
|
||||||
|
|
||||||
+ (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings;
|
+ (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings;
|
||||||
|
+ (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken;
|
||||||
+ (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)notification;
|
+ (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)notification;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
@ -12,7 +12,18 @@
|
|||||||
#import "RCTBridge.h"
|
#import "RCTBridge.h"
|
||||||
#import "RCTEventDispatcher.h"
|
#import "RCTEventDispatcher.h"
|
||||||
|
|
||||||
|
#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_8_0
|
||||||
|
|
||||||
|
#define UIUserNotificationTypeAlert UIRemoteNotificationTypeAlert
|
||||||
|
#define UIUserNotificationTypeBadge UIRemoteNotificationTypeBadge
|
||||||
|
#define UIUserNotificationTypeSound UIRemoteNotificationTypeSound
|
||||||
|
#define UIUserNotificationTypeNone UIRemoteNotificationTypeNone
|
||||||
|
#define UIUserNotificationType UIRemoteNotificationType
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
NSString *const RCTRemoteNotificationReceived = @"RemoteNotificationReceived";
|
NSString *const RCTRemoteNotificationReceived = @"RemoteNotificationReceived";
|
||||||
|
NSString *const RCTRemoteNotificationsRegistered = @"RemoteNotificationsRegistered";
|
||||||
|
|
||||||
@implementation RCTPushNotificationManager
|
@implementation RCTPushNotificationManager
|
||||||
{
|
{
|
||||||
@ -30,6 +41,10 @@ RCT_EXPORT_MODULE()
|
|||||||
selector:@selector(handleRemoteNotificationReceived:)
|
selector:@selector(handleRemoteNotificationReceived:)
|
||||||
name:RCTRemoteNotificationReceived
|
name:RCTRemoteNotificationReceived
|
||||||
object:nil];
|
object:nil];
|
||||||
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||||
|
selector:@selector(handleRemoteNotificationsRegistered:)
|
||||||
|
name:RCTRemoteNotificationsRegistered
|
||||||
|
object:nil];
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
@ -52,6 +67,21 @@ RCT_EXPORT_MODULE()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
+ (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
|
||||||
|
{
|
||||||
|
NSMutableString *hexString = [NSMutableString string];
|
||||||
|
const unsigned char *bytes = [deviceToken bytes];
|
||||||
|
for (int i = 0; i < [deviceToken length]; i++) {
|
||||||
|
[hexString appendFormat:@"%02x", bytes[i]];
|
||||||
|
}
|
||||||
|
NSDictionary *userInfo = @{
|
||||||
|
@"deviceToken" : [hexString copy]
|
||||||
|
};
|
||||||
|
[[NSNotificationCenter defaultCenter] postNotificationName:RCTRemoteNotificationsRegistered
|
||||||
|
object:self
|
||||||
|
userInfo:userInfo];
|
||||||
|
}
|
||||||
|
|
||||||
+ (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)notification
|
+ (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)notification
|
||||||
{
|
{
|
||||||
[[NSNotificationCenter defaultCenter] postNotificationName:RCTRemoteNotificationReceived
|
[[NSNotificationCenter defaultCenter] postNotificationName:RCTRemoteNotificationReceived
|
||||||
@ -65,6 +95,12 @@ RCT_EXPORT_MODULE()
|
|||||||
body:[notification userInfo]];
|
body:[notification userInfo]];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)handleRemoteNotificationsRegistered:(NSNotification *)notification
|
||||||
|
{
|
||||||
|
[_bridge.eventDispatcher sendDeviceEventWithName:@"remoteNotificationsRegistered"
|
||||||
|
body:[notification userInfo]];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the application icon badge number on the home screen
|
* Update the application icon badge number on the home screen
|
||||||
*/
|
*/
|
||||||
@ -83,36 +119,35 @@ RCT_EXPORT_METHOD(getApplicationIconBadgeNumber:(RCTResponseSenderBlock)callback
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
RCT_EXPORT_METHOD(requestPermissions)
|
RCT_EXPORT_METHOD(requestPermissions:(NSDictionary *)permissions)
|
||||||
{
|
{
|
||||||
Class _UIUserNotificationSettings;
|
UIUserNotificationType types = UIRemoteNotificationTypeNone;
|
||||||
if ((_UIUserNotificationSettings = NSClassFromString(@"UIUserNotificationSettings"))) {
|
if (permissions) {
|
||||||
UIUserNotificationType types = UIUserNotificationTypeSound | UIUserNotificationTypeBadge | UIUserNotificationTypeAlert;
|
if ([permissions[@"alert"] boolValue]) {
|
||||||
UIUserNotificationSettings *notificationSettings = [_UIUserNotificationSettings settingsForTypes:types categories:nil];
|
types |= UIUserNotificationTypeAlert;
|
||||||
[[UIApplication sharedApplication] registerUserNotificationSettings:notificationSettings];
|
}
|
||||||
|
if ([permissions[@"badge"] boolValue]) {
|
||||||
|
types |= UIUserNotificationTypeBadge;
|
||||||
|
}
|
||||||
|
if ([permissions[@"sound"] boolValue]) {
|
||||||
|
types |= UIUserNotificationTypeSound;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
types = UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound;
|
||||||
|
}
|
||||||
|
|
||||||
#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_8_0
|
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_8_0
|
||||||
|
id notificationSettings = [UIUserNotificationSettings settingsForTypes:types categories:nil];
|
||||||
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:
|
[[UIApplication sharedApplication] registerUserNotificationSettings:notificationSettings];
|
||||||
UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert];
|
[[UIApplication sharedApplication] registerForRemoteNotifications];
|
||||||
|
#else
|
||||||
|
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:types];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
RCT_EXPORT_METHOD(checkPermissions:(RCTResponseSenderBlock)callback)
|
RCT_EXPORT_METHOD(checkPermissions:(RCTResponseSenderBlock)callback)
|
||||||
{
|
{
|
||||||
|
|
||||||
#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_8_0
|
|
||||||
|
|
||||||
#define UIUserNotificationTypeAlert UIRemoteNotificationTypeAlert
|
|
||||||
#define UIUserNotificationTypeBadge UIRemoteNotificationTypeBadge
|
|
||||||
#define UIUserNotificationTypeSound UIRemoteNotificationTypeSound
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
NSUInteger types = 0;
|
NSUInteger types = 0;
|
||||||
if ([UIApplication instancesRespondToSelector:@selector(currentUserNotificationSettings)]) {
|
if ([UIApplication instancesRespondToSelector:@selector(currentUserNotificationSettings)]) {
|
||||||
types = [[[UIApplication sharedApplication] currentUserNotificationSettings] types];
|
types = [[[UIApplication sharedApplication] currentUserNotificationSettings] types];
|
||||||
|
@ -35,7 +35,11 @@
|
|||||||
sanitizedAppName = [sanitizedAppName stringByReplacingOccurrencesOfString:@"\\" withString:@"-"];
|
sanitizedAppName = [sanitizedAppName stringByReplacingOccurrencesOfString:@"\\" withString:@"-"];
|
||||||
_testController = [[FBSnapshotTestController alloc] initWithTestName:sanitizedAppName];
|
_testController = [[FBSnapshotTestController alloc] initWithTestName:sanitizedAppName];
|
||||||
_testController.referenceImagesDirectory = referenceDir;
|
_testController.referenceImagesDirectory = referenceDir;
|
||||||
|
#if RUNNING_ON_CI
|
||||||
|
_scriptURL = [[NSBundle bundleForClass:[RCTBridge class]] URLForResource:@"main" withExtension:@"jsbundle"];
|
||||||
|
#else
|
||||||
_scriptURL = [NSURL URLWithString:[NSString stringWithFormat:@"http://localhost:8081/%@.includeRequire.runModule.bundle?dev=true", app]];
|
_scriptURL = [NSURL URLWithString:[NSString stringWithFormat:@"http://localhost:8081/%@.includeRequire.runModule.bundle?dev=true", app]];
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
38
Libraries/ReactIOS/InspectorOverlay/BorderBox.js
Normal file
38
Libraries/ReactIOS/InspectorOverlay/BorderBox.js
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
/**
|
||||||
|
* 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 BorderBox
|
||||||
|
* @flow
|
||||||
|
*/
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var React = require('React');
|
||||||
|
var View = require('View');
|
||||||
|
|
||||||
|
class BorderBox extends React.Component {
|
||||||
|
render() {
|
||||||
|
var box = this.props.box;
|
||||||
|
if (!box) {
|
||||||
|
return this.props.children;
|
||||||
|
}
|
||||||
|
var style = {
|
||||||
|
borderTopWidth: box.top,
|
||||||
|
borderBottomWidth: box.bottom,
|
||||||
|
borderLeftWidth: box.left,
|
||||||
|
borderRightWidth: box.right,
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<View style={[style, this.props.style]}>
|
||||||
|
{this.props.children}
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = BorderBox;
|
||||||
|
|
113
Libraries/ReactIOS/InspectorOverlay/BoxInspector.js
Normal file
113
Libraries/ReactIOS/InspectorOverlay/BoxInspector.js
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
/**
|
||||||
|
* 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 BoxInspector
|
||||||
|
* @flow
|
||||||
|
*/
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var React = require('React');
|
||||||
|
var StyleSheet = require('StyleSheet');
|
||||||
|
var Text = require('Text');
|
||||||
|
var View = require('View');
|
||||||
|
var resolveBoxStyle = require('resolveBoxStyle');
|
||||||
|
|
||||||
|
var blank = {
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
bottom: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
class BoxInspector extends React.Component {
|
||||||
|
render() {
|
||||||
|
var frame = this.props.frame;
|
||||||
|
var style = this.props.style;
|
||||||
|
var margin = style && resolveBoxStyle('margin', style) || blank;
|
||||||
|
var padding = style && resolveBoxStyle('padding', style) || blank;
|
||||||
|
return (
|
||||||
|
<BoxContainer title="margin" titleStyle={styles.marginLabel} box={margin}>
|
||||||
|
<BoxContainer title="padding" box={padding}>
|
||||||
|
<View>
|
||||||
|
<Text style={styles.innerText}>
|
||||||
|
({frame.left}, {frame.top})
|
||||||
|
</Text>
|
||||||
|
<Text style={styles.innerText}>
|
||||||
|
{frame.width} × {frame.height}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
</BoxContainer>
|
||||||
|
</BoxContainer>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class BoxContainer extends React.Component {
|
||||||
|
render() {
|
||||||
|
var box = this.props.box;
|
||||||
|
return (
|
||||||
|
<View style={styles.box}>
|
||||||
|
<View style={styles.row}>
|
||||||
|
<Text style={[this.props.titleStyle, styles.label]}>{this.props.title}</Text>
|
||||||
|
<Text style={styles.boxText}>{box.top}</Text>
|
||||||
|
</View>
|
||||||
|
<View style={styles.row}>
|
||||||
|
<Text style={styles.boxText}>{box.left}</Text>
|
||||||
|
{this.props.children}
|
||||||
|
<Text style={styles.boxText}>{box.right}</Text>
|
||||||
|
</View>
|
||||||
|
<Text style={styles.boxText}>{box.bottom}</Text>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var styles = StyleSheet.create({
|
||||||
|
row: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'space-around',
|
||||||
|
},
|
||||||
|
marginLabel: {
|
||||||
|
width: 60,
|
||||||
|
},
|
||||||
|
label: {
|
||||||
|
fontSize: 10,
|
||||||
|
color: 'rgb(255,100,0)',
|
||||||
|
marginLeft: 5,
|
||||||
|
flex: 1,
|
||||||
|
textAlign: 'left',
|
||||||
|
top: -3,
|
||||||
|
},
|
||||||
|
buffer: {
|
||||||
|
fontSize: 10,
|
||||||
|
color: 'yellow',
|
||||||
|
flex: 1,
|
||||||
|
textAlign: 'center',
|
||||||
|
},
|
||||||
|
innerText: {
|
||||||
|
color: 'yellow',
|
||||||
|
fontSize: 12,
|
||||||
|
textAlign: 'center',
|
||||||
|
width: 70,
|
||||||
|
},
|
||||||
|
box: {
|
||||||
|
borderWidth: 1,
|
||||||
|
borderColor: 'grey',
|
||||||
|
},
|
||||||
|
boxText: {
|
||||||
|
color: 'white',
|
||||||
|
fontSize: 12,
|
||||||
|
marginHorizontal: 3,
|
||||||
|
marginVertical: 2,
|
||||||
|
textAlign: 'center',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = BoxInspector;
|
||||||
|
|
74
Libraries/ReactIOS/InspectorOverlay/ElementBox.js
Normal file
74
Libraries/ReactIOS/InspectorOverlay/ElementBox.js
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
/**
|
||||||
|
* 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 ElementBox
|
||||||
|
* @flow
|
||||||
|
*/
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var React = require('React');
|
||||||
|
var View = require('View');
|
||||||
|
var StyleSheet = require('StyleSheet');
|
||||||
|
var BorderBox = require('BorderBox');
|
||||||
|
var resolveBoxStyle = require('resolveBoxStyle');
|
||||||
|
|
||||||
|
var flattenStyle = require('flattenStyle');
|
||||||
|
|
||||||
|
class ElementBox extends React.Component {
|
||||||
|
render() {
|
||||||
|
var style = flattenStyle(this.props.style) || {};
|
||||||
|
var margin = resolveBoxStyle('margin', style);
|
||||||
|
var padding = resolveBoxStyle('padding', style);
|
||||||
|
var frameStyle = this.props.frame;
|
||||||
|
if (margin) {
|
||||||
|
frameStyle = {
|
||||||
|
top: frameStyle.top - margin.top,
|
||||||
|
left: frameStyle.left - margin.left,
|
||||||
|
height: frameStyle.height + margin.top + margin.bottom,
|
||||||
|
width: frameStyle.width + margin.left + margin.right,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
var contentStyle = {
|
||||||
|
width: this.props.frame.width,
|
||||||
|
height: this.props.frame.height,
|
||||||
|
};
|
||||||
|
if (padding) {
|
||||||
|
contentStyle = {
|
||||||
|
width: contentStyle.width - padding.left - padding.right,
|
||||||
|
height: contentStyle.height - padding.top - padding.bottom,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<View style={[styles.frame, frameStyle]} pointerEvents="none">
|
||||||
|
<BorderBox box={margin} style={styles.margin}>
|
||||||
|
<BorderBox box={padding} style={styles.padding}>
|
||||||
|
<View style={[styles.content, contentStyle]} />
|
||||||
|
</BorderBox>
|
||||||
|
</BorderBox>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var styles = StyleSheet.create({
|
||||||
|
frame: {
|
||||||
|
position: 'absolute',
|
||||||
|
},
|
||||||
|
content: {
|
||||||
|
backgroundColor: 'rgba(200, 230, 255, 0.8)',
|
||||||
|
},
|
||||||
|
padding: {
|
||||||
|
borderColor: 'rgba(77, 255, 0, 0.3)',
|
||||||
|
},
|
||||||
|
margin: {
|
||||||
|
borderColor: 'rgba(255, 132, 0, 0.3)',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = ElementBox;
|
||||||
|
|
105
Libraries/ReactIOS/InspectorOverlay/ElementProperties.js
Normal file
105
Libraries/ReactIOS/InspectorOverlay/ElementProperties.js
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
/**
|
||||||
|
* 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 ElementProperties
|
||||||
|
* @flow
|
||||||
|
*/
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var React = require('React');
|
||||||
|
var StyleSheet = require('StyleSheet');
|
||||||
|
var Text = require('Text');
|
||||||
|
var View = require('View');
|
||||||
|
var PropTypes = require('ReactPropTypes');
|
||||||
|
var BoxInspector = require('BoxInspector');
|
||||||
|
var StyleInspector = require('StyleInspector');
|
||||||
|
var TouchableHighlight = require('TouchableHighlight');
|
||||||
|
var TouchableWithoutFeedback = require('TouchableWithoutFeedback');
|
||||||
|
|
||||||
|
var flattenStyle = require('flattenStyle');
|
||||||
|
var mapWithSeparator = require('mapWithSeparator');
|
||||||
|
|
||||||
|
var ElementProperties = React.createClass({
|
||||||
|
propTypes: {
|
||||||
|
hierarchy: PropTypes.array.isRequired,
|
||||||
|
style: PropTypes.array.isRequired,
|
||||||
|
},
|
||||||
|
|
||||||
|
render: function() {
|
||||||
|
var style = flattenStyle(this.props.style);
|
||||||
|
var selection = this.props.selection;
|
||||||
|
// Without the `TouchableWithoutFeedback`, taps on this inspector pane
|
||||||
|
// would change the inspected element to whatever is under the inspector
|
||||||
|
return (
|
||||||
|
<TouchableWithoutFeedback>
|
||||||
|
<View style={styles.info}>
|
||||||
|
<View style={styles.breadcrumb}>
|
||||||
|
{mapWithSeparator(
|
||||||
|
this.props.hierarchy,
|
||||||
|
(item, i) => (
|
||||||
|
<TouchableHighlight
|
||||||
|
style={[styles.breadItem, i === selection && styles.selected]}
|
||||||
|
onPress={() => this.props.setSelection(i)}>
|
||||||
|
<Text style={styles.breadItemText}>
|
||||||
|
{item.getName ? item.getName() : 'Unknown'}
|
||||||
|
</Text>
|
||||||
|
</TouchableHighlight>
|
||||||
|
),
|
||||||
|
() => <Text style={styles.breadSep}>▸</Text>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
<View style={styles.row}>
|
||||||
|
<StyleInspector style={style} />
|
||||||
|
<BoxInspector style={style} frame={this.props.frame} />
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</TouchableWithoutFeedback>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var styles = StyleSheet.create({
|
||||||
|
breadSep: {
|
||||||
|
fontSize: 8,
|
||||||
|
color: 'white',
|
||||||
|
},
|
||||||
|
breadcrumb: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
flexWrap: 'wrap',
|
||||||
|
marginBottom: 5,
|
||||||
|
},
|
||||||
|
selected: {
|
||||||
|
borderColor: 'white',
|
||||||
|
borderRadius: 5,
|
||||||
|
},
|
||||||
|
breadItem: {
|
||||||
|
borderWidth: 1,
|
||||||
|
borderColor: 'transparent',
|
||||||
|
marginHorizontal: 2,
|
||||||
|
},
|
||||||
|
breadItemText: {
|
||||||
|
fontSize: 10,
|
||||||
|
color: 'white',
|
||||||
|
marginHorizontal: 5,
|
||||||
|
},
|
||||||
|
row: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
},
|
||||||
|
info: {
|
||||||
|
backgroundColor: 'rgba(0, 0, 0, 0.7)',
|
||||||
|
padding: 10,
|
||||||
|
},
|
||||||
|
path: {
|
||||||
|
color: 'white',
|
||||||
|
fontSize: 9,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = ElementProperties;
|
@ -17,12 +17,16 @@ var StyleSheet = require('StyleSheet');
|
|||||||
var Text = require('Text');
|
var Text = require('Text');
|
||||||
var UIManager = require('NativeModules').UIManager;
|
var UIManager = require('NativeModules').UIManager;
|
||||||
var View = require('View');
|
var View = require('View');
|
||||||
|
var ElementBox = require('ElementBox');
|
||||||
|
var ElementProperties = require('ElementProperties');
|
||||||
|
|
||||||
var InspectorOverlay = React.createClass({
|
var InspectorOverlay = React.createClass({
|
||||||
getInitialState: function() {
|
getInitialState: function() {
|
||||||
return {
|
return {
|
||||||
frame: null,
|
frame: null,
|
||||||
|
pointerY: 0,
|
||||||
hierarchy: [],
|
hierarchy: [],
|
||||||
|
selection: -1,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -33,15 +37,34 @@ var InspectorOverlay = React.createClass({
|
|||||||
[locationX, locationY],
|
[locationX, locationY],
|
||||||
(nativeViewTag, left, top, width, height) => {
|
(nativeViewTag, left, top, width, height) => {
|
||||||
var instance = Inspector.findInstanceByNativeTag(this.props.rootTag, nativeViewTag);
|
var instance = Inspector.findInstanceByNativeTag(this.props.rootTag, nativeViewTag);
|
||||||
|
if (!instance) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
var hierarchy = Inspector.getOwnerHierarchy(instance);
|
var hierarchy = Inspector.getOwnerHierarchy(instance);
|
||||||
|
var publicInstance = instance.getPublicInstance();
|
||||||
this.setState({
|
this.setState({
|
||||||
hierarchy,
|
hierarchy,
|
||||||
frame: {left, top, width, height}
|
pointerY: locationY,
|
||||||
|
selection: hierarchy.length - 1,
|
||||||
|
frame: {left, top, width, height},
|
||||||
|
style: publicInstance.props ? publicInstance.props.style : {},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
setSelection(i) {
|
||||||
|
var instance = this.state.hierarchy[i];
|
||||||
|
var publicInstance = instance.getPublicInstance();
|
||||||
|
UIManager.measure(React.findNodeHandle(instance), (x, y, width, height, left, top) => {
|
||||||
|
this.setState({
|
||||||
|
frame: {left, top, width, height},
|
||||||
|
style: publicInstance.props ? publicInstance.props.style : {},
|
||||||
|
selection: i,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
shouldSetResponser: function(e) {
|
shouldSetResponser: function(e) {
|
||||||
this.findViewForTouchEvent(e);
|
this.findViewForTouchEvent(e);
|
||||||
return true;
|
return true;
|
||||||
@ -49,18 +72,32 @@ var InspectorOverlay = React.createClass({
|
|||||||
|
|
||||||
render: function() {
|
render: function() {
|
||||||
var content = [];
|
var content = [];
|
||||||
|
var justifyContent = 'flex-end';
|
||||||
|
|
||||||
if (this.state.frame) {
|
if (this.state.frame) {
|
||||||
var distanceToTop = this.state.frame.top;
|
var distanceToTop = this.state.pointerY;
|
||||||
var distanceToBottom = Dimensions.get('window').height -
|
var distanceToBottom = Dimensions.get('window').height - distanceToTop;
|
||||||
(this.state.frame.top + this.state.frame.height);
|
|
||||||
|
|
||||||
var justifyContent = distanceToTop > distanceToBottom
|
justifyContent = distanceToTop > distanceToBottom
|
||||||
? 'flex-start'
|
? 'flex-start'
|
||||||
: 'flex-end';
|
: 'flex-end';
|
||||||
|
|
||||||
content.push(<View pointerEvents="none" style={[styles.frame, this.state.frame]} />);
|
content.push(<ElementBox frame={this.state.frame} style={this.state.style} />);
|
||||||
content.push(<ElementProperties hierarchy={this.state.hierarchy} />);
|
content.push(
|
||||||
|
<ElementProperties
|
||||||
|
style={this.state.style}
|
||||||
|
frame={this.state.frame}
|
||||||
|
hierarchy={this.state.hierarchy}
|
||||||
|
selection={this.state.selection}
|
||||||
|
setSelection={this.setSelection}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
content.push(
|
||||||
|
<View style={styles.welcomeMessage}>
|
||||||
|
<Text style={styles.welcomeText}>Welcome to the inspector! Tap something to inspect it.</Text>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<View
|
<View
|
||||||
@ -73,42 +110,23 @@ var InspectorOverlay = React.createClass({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
var ElementProperties = React.createClass({
|
|
||||||
render: function() {
|
|
||||||
var path = this.props.hierarchy.map((instance) => {
|
|
||||||
return instance.getName ? instance.getName() : 'Unknown';
|
|
||||||
}).join(' > ');
|
|
||||||
return (
|
|
||||||
<View style={styles.info}>
|
|
||||||
<Text style={styles.path}>
|
|
||||||
{path}
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
var styles = StyleSheet.create({
|
var styles = StyleSheet.create({
|
||||||
|
welcomeMessage: {
|
||||||
|
backgroundColor: 'rgba(0, 0, 0, 0.7)',
|
||||||
|
padding: 10,
|
||||||
|
paddingVertical: 50,
|
||||||
|
},
|
||||||
|
welcomeText: {
|
||||||
|
color: 'white',
|
||||||
|
},
|
||||||
inspector: {
|
inspector: {
|
||||||
backgroundColor: 'rgba(255,255,255,0.8)',
|
backgroundColor: 'rgba(255,255,255,0.0)',
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
left: 0,
|
left: 0,
|
||||||
top: 0,
|
top: 0,
|
||||||
right: 0,
|
right: 0,
|
||||||
bottom: 0,
|
bottom: 0,
|
||||||
},
|
},
|
||||||
frame: {
|
|
||||||
position: 'absolute',
|
|
||||||
backgroundColor: 'rgba(155,155,255,0.3)',
|
|
||||||
},
|
|
||||||
info: {
|
|
||||||
backgroundColor: 'rgba(0, 0, 0, 0.7)',
|
|
||||||
padding: 10,
|
|
||||||
},
|
|
||||||
path: {
|
|
||||||
color: 'white',
|
|
||||||
fontSize: 9,
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = InspectorOverlay;
|
module.exports = InspectorOverlay;
|
63
Libraries/ReactIOS/InspectorOverlay/StyleInspector.js
Normal file
63
Libraries/ReactIOS/InspectorOverlay/StyleInspector.js
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
/**
|
||||||
|
* 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 StyleInspector
|
||||||
|
* @flow
|
||||||
|
*/
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var React = require('React');
|
||||||
|
var StyleSheet = require('StyleSheet');
|
||||||
|
var Text = require('Text');
|
||||||
|
var View = require('View');
|
||||||
|
|
||||||
|
class StyleInspector extends React.Component {
|
||||||
|
render() {
|
||||||
|
if (!this.props.style) {
|
||||||
|
return <Text style={styles.noStyle}>No style</Text>;
|
||||||
|
}
|
||||||
|
var names = Object.keys(this.props.style);
|
||||||
|
return (
|
||||||
|
<View style={styles.container}>
|
||||||
|
<View>
|
||||||
|
{names.map(name => <Text style={styles.attr}>{name}:</Text>)}
|
||||||
|
</View>
|
||||||
|
<View>
|
||||||
|
{names.map(name => <Text style={styles.value}>{this.props.style[name]}</Text>)}
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
},
|
||||||
|
row: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'space-around',
|
||||||
|
},
|
||||||
|
attr: {
|
||||||
|
fontSize: 10,
|
||||||
|
color: '#ccc',
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
fontSize: 10,
|
||||||
|
color: 'white',
|
||||||
|
marginLeft: 10,
|
||||||
|
},
|
||||||
|
noStyle: {
|
||||||
|
color: 'white',
|
||||||
|
fontSize: 10,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = StyleInspector;
|
||||||
|
|
59
Libraries/ReactIOS/InspectorOverlay/resolveBoxStyle.js
Normal file
59
Libraries/ReactIOS/InspectorOverlay/resolveBoxStyle.js
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
/**
|
||||||
|
* 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 resolveBoxStyle
|
||||||
|
* @flow
|
||||||
|
*/
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve a style property into it's component parts, e.g.
|
||||||
|
*
|
||||||
|
* resolveProperties('margin', {margin: 5, marginBottom: 10})
|
||||||
|
* ->
|
||||||
|
* {top: 5, left: 5, right: 5, bottom: 10}
|
||||||
|
*
|
||||||
|
* If none are set, returns false.
|
||||||
|
*/
|
||||||
|
function resolveBoxStyle(prefix: String, style: Object): ?Object {
|
||||||
|
var res = {};
|
||||||
|
var subs = ['top', 'left', 'bottom', 'right'];
|
||||||
|
var set = false;
|
||||||
|
subs.forEach(sub => {
|
||||||
|
res[sub] = style[prefix] || 0;
|
||||||
|
});
|
||||||
|
if (style[prefix]) {
|
||||||
|
set = true;
|
||||||
|
}
|
||||||
|
if (style[prefix + 'Vertical']) {
|
||||||
|
res.top = res.bottom = style[prefix + 'Vertical'];
|
||||||
|
set = true;
|
||||||
|
}
|
||||||
|
if (style[prefix + 'Horizontal']) {
|
||||||
|
res.left = res.right = style[prefix + 'Horizontal'];
|
||||||
|
set = true;
|
||||||
|
}
|
||||||
|
subs.forEach(sub => {
|
||||||
|
var val = style[prefix + capFirst(sub)];
|
||||||
|
if (val) {
|
||||||
|
res[sub] = val;
|
||||||
|
set = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (!set) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
function capFirst(text) {
|
||||||
|
return text[0].toUpperCase() + text.slice(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = resolveBoxStyle;
|
||||||
|
|
19
Libraries/Utilities/mapWithSeparator.js
Normal file
19
Libraries/Utilities/mapWithSeparator.js
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2004-present Facebook. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* @providesModule mapWithSeparator
|
||||||
|
*/
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
function mapWithSeparator(array, valueFunction, separatorFunction) {
|
||||||
|
var results = [];
|
||||||
|
for (var i = 0; i < array.length; i++) {
|
||||||
|
results.push(valueFunction(array[i], i, array));
|
||||||
|
if (i !== array.length - 1) {
|
||||||
|
results.push(separatorFunction(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = mapWithSeparator;
|
9
Libraries/react-native/react-native.js
vendored
9
Libraries/react-native/react-native.js
vendored
@ -24,11 +24,12 @@ var ReactNative = Object.assign(Object.create(require('React')), {
|
|||||||
Image: require('Image'),
|
Image: require('Image'),
|
||||||
ListView: require('ListView'),
|
ListView: require('ListView'),
|
||||||
MapView: require('MapView'),
|
MapView: require('MapView'),
|
||||||
|
Navigator: require('Navigator'),
|
||||||
NavigatorIOS: require('NavigatorIOS'),
|
NavigatorIOS: require('NavigatorIOS'),
|
||||||
PickerIOS: require('PickerIOS'),
|
PickerIOS: require('PickerIOS'),
|
||||||
Navigator: require('Navigator'),
|
ProgressViewIOS: require('ProgressViewIOS'),
|
||||||
SegmentedControlIOS: require('SegmentedControlIOS'),
|
|
||||||
ScrollView: require('ScrollView'),
|
ScrollView: require('ScrollView'),
|
||||||
|
SegmentedControlIOS: require('SegmentedControlIOS'),
|
||||||
SliderIOS: require('SliderIOS'),
|
SliderIOS: require('SliderIOS'),
|
||||||
SwitchIOS: require('SwitchIOS'),
|
SwitchIOS: require('SwitchIOS'),
|
||||||
TabBarIOS: require('TabBarIOS'),
|
TabBarIOS: require('TabBarIOS'),
|
||||||
@ -47,12 +48,12 @@ var ReactNative = Object.assign(Object.create(require('React')), {
|
|||||||
AsyncStorage: require('AsyncStorage'),
|
AsyncStorage: require('AsyncStorage'),
|
||||||
CameraRoll: require('CameraRoll'),
|
CameraRoll: require('CameraRoll'),
|
||||||
InteractionManager: require('InteractionManager'),
|
InteractionManager: require('InteractionManager'),
|
||||||
LinkingIOS: require('LinkingIOS'),
|
|
||||||
LayoutAnimation: require('LayoutAnimation'),
|
LayoutAnimation: require('LayoutAnimation'),
|
||||||
|
LinkingIOS: require('LinkingIOS'),
|
||||||
NetInfo: require('NetInfo'),
|
NetInfo: require('NetInfo'),
|
||||||
|
PanResponder: require('PanResponder'),
|
||||||
PixelRatio: require('PixelRatio'),
|
PixelRatio: require('PixelRatio'),
|
||||||
PushNotificationIOS: require('PushNotificationIOS'),
|
PushNotificationIOS: require('PushNotificationIOS'),
|
||||||
PanResponder: require('PanResponder'),
|
|
||||||
StatusBarIOS: require('StatusBarIOS'),
|
StatusBarIOS: require('StatusBarIOS'),
|
||||||
StyleSheet: require('StyleSheet'),
|
StyleSheet: require('StyleSheet'),
|
||||||
VibrationIOS: require('VibrationIOS'),
|
VibrationIOS: require('VibrationIOS'),
|
||||||
|
@ -232,6 +232,8 @@ var PRESS_EXPAND_PX = 20;
|
|||||||
|
|
||||||
var LONG_PRESS_THRESHOLD = 500;
|
var LONG_PRESS_THRESHOLD = 500;
|
||||||
|
|
||||||
|
var LONG_PRESS_DELAY_MS = LONG_PRESS_THRESHOLD - HIGHLIGHT_DELAY_MS;
|
||||||
|
|
||||||
var LONG_PRESS_ALLOWED_MOVEMENT = 10;
|
var LONG_PRESS_ALLOWED_MOVEMENT = 10;
|
||||||
|
|
||||||
// Default amount "active" region protrudes beyond box
|
// Default amount "active" region protrudes beyond box
|
||||||
@ -276,7 +278,7 @@ var LONG_PRESS_ALLOWED_MOVEMENT = 10;
|
|||||||
* +
|
* +
|
||||||
* | RESPONDER_GRANT (HitRect)
|
* | RESPONDER_GRANT (HitRect)
|
||||||
* v
|
* v
|
||||||
* +---------------------------+ DELAY +-------------------------+ T - DELAY +------------------------------+
|
* +---------------------------+ DELAY +-------------------------+ T + DELAY +------------------------------+
|
||||||
* |RESPONDER_INACTIVE_PRESS_IN|+-------->|RESPONDER_ACTIVE_PRESS_IN| +------------> |RESPONDER_ACTIVE_LONG_PRESS_IN|
|
* |RESPONDER_INACTIVE_PRESS_IN|+-------->|RESPONDER_ACTIVE_PRESS_IN| +------------> |RESPONDER_ACTIVE_LONG_PRESS_IN|
|
||||||
* +---------------------------+ +-------------------------+ +------------------------------+
|
* +---------------------------+ +-------------------------+ +------------------------------+
|
||||||
* + ^ + ^ + ^
|
* + ^ + ^ + ^
|
||||||
@ -288,7 +290,7 @@ var LONG_PRESS_ALLOWED_MOVEMENT = 10;
|
|||||||
* |RESPONDER_INACTIVE_PRESS_OUT|+------->|RESPONDER_ACTIVE_PRESS_OUT| |RESPONDER_ACTIVE_LONG_PRESS_OUT|
|
* |RESPONDER_INACTIVE_PRESS_OUT|+------->|RESPONDER_ACTIVE_PRESS_OUT| |RESPONDER_ACTIVE_LONG_PRESS_OUT|
|
||||||
* +----------------------------+ +--------------------------+ +-------------------------------+
|
* +----------------------------+ +--------------------------+ +-------------------------------+
|
||||||
*
|
*
|
||||||
* T - DELAY => LONG_PRESS_THRESHOLD - DELAY
|
* T + DELAY => LONG_PRESS_DELAY_MS + DELAY
|
||||||
*
|
*
|
||||||
* Not drawn are the side effects of each transition. The most important side
|
* Not drawn are the side effects of each transition. The most important side
|
||||||
* effect is the `touchableHandlePress` abstract method invocation that occurs
|
* effect is the `touchableHandlePress` abstract method invocation that occurs
|
||||||
@ -348,12 +350,16 @@ var TouchableMixin = {
|
|||||||
// event to make sure it doesn't get reused in the event object pool.
|
// event to make sure it doesn't get reused in the event object pool.
|
||||||
e.persist();
|
e.persist();
|
||||||
|
|
||||||
|
this.pressOutDelayTimeout && clearTimeout(this.pressOutDelayTimeout);
|
||||||
|
this.pressOutDelayTimeout = null;
|
||||||
|
|
||||||
this.state.touchable.touchState = States.NOT_RESPONDER;
|
this.state.touchable.touchState = States.NOT_RESPONDER;
|
||||||
this.state.touchable.responderID = dispatchID;
|
this.state.touchable.responderID = dispatchID;
|
||||||
this._receiveSignal(Signals.RESPONDER_GRANT, e);
|
this._receiveSignal(Signals.RESPONDER_GRANT, e);
|
||||||
var delayMS =
|
var delayMS =
|
||||||
this.touchableGetHighlightDelayMS !== undefined ?
|
this.touchableGetHighlightDelayMS !== undefined ?
|
||||||
this.touchableGetHighlightDelayMS() : HIGHLIGHT_DELAY_MS;
|
Math.max(this.touchableGetHighlightDelayMS(), 0) : HIGHLIGHT_DELAY_MS;
|
||||||
|
delayMS = isNaN(delayMS) ? HIGHLIGHT_DELAY_MS : delayMS;
|
||||||
if (delayMS !== 0) {
|
if (delayMS !== 0) {
|
||||||
this.touchableDelayTimeout = setTimeout(
|
this.touchableDelayTimeout = setTimeout(
|
||||||
this._handleDelay.bind(this, e),
|
this._handleDelay.bind(this, e),
|
||||||
@ -363,9 +369,13 @@ var TouchableMixin = {
|
|||||||
this._handleDelay(e);
|
this._handleDelay(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var longDelayMS =
|
||||||
|
this.touchableGetLongPressDelayMS !== undefined ?
|
||||||
|
Math.max(this.touchableGetLongPressDelayMS(), 10) : LONG_PRESS_DELAY_MS;
|
||||||
|
longDelayMS = isNaN(longDelayMS) ? LONG_PRESS_DELAY_MS : longDelayMS;
|
||||||
this.longPressDelayTimeout = setTimeout(
|
this.longPressDelayTimeout = setTimeout(
|
||||||
this._handleLongDelay.bind(this, e),
|
this._handleLongDelay.bind(this, e),
|
||||||
LONG_PRESS_THRESHOLD - delayMS
|
longDelayMS + delayMS
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -632,8 +642,14 @@ var TouchableMixin = {
|
|||||||
if (newIsHighlight && !curIsHighlight) {
|
if (newIsHighlight && !curIsHighlight) {
|
||||||
this._savePressInLocation(e);
|
this._savePressInLocation(e);
|
||||||
this.touchableHandleActivePressIn && this.touchableHandleActivePressIn();
|
this.touchableHandleActivePressIn && this.touchableHandleActivePressIn();
|
||||||
} else if (!newIsHighlight && curIsHighlight) {
|
} else if (!newIsHighlight && curIsHighlight && this.touchableHandleActivePressOut) {
|
||||||
this.touchableHandleActivePressOut && this.touchableHandleActivePressOut();
|
if (this.touchableGetPressOutDelayMS && this.touchableGetPressOutDelayMS()) {
|
||||||
|
this.pressOutDelayTimeout = this.setTimeout(function() {
|
||||||
|
this.touchableHandleActivePressOut();
|
||||||
|
}, this.touchableGetPressOutDelayMS());
|
||||||
|
} else {
|
||||||
|
this.touchableHandleActivePressOut();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsPressingIn[curState] && signal === Signals.RESPONDER_RELEASE) {
|
if (IsPressingIn[curState] && signal === Signals.RESPONDER_RELEASE) {
|
||||||
|
@ -244,30 +244,19 @@ static NSArray *RCTBridgeModuleClassesByModuleID(void)
|
|||||||
|
|
||||||
@implementation RCTModuleMethod
|
@implementation RCTModuleMethod
|
||||||
{
|
{
|
||||||
BOOL _isClassMethod;
|
|
||||||
Class _moduleClass;
|
Class _moduleClass;
|
||||||
SEL _selector;
|
SEL _selector;
|
||||||
NSMethodSignature *_methodSignature;
|
NSMethodSignature *_methodSignature;
|
||||||
NSArray *_argumentBlocks;
|
NSArray *_argumentBlocks;
|
||||||
NSString *_methodName;
|
|
||||||
dispatch_block_t _methodQueue;
|
dispatch_block_t _methodQueue;
|
||||||
}
|
}
|
||||||
|
|
||||||
static NSString *RCTStringUpToFirstArgument(NSString *methodName)
|
|
||||||
{
|
|
||||||
NSRange colonRange = [methodName rangeOfString:@":"];
|
|
||||||
if (colonRange.length) {
|
|
||||||
methodName = [methodName substringToIndex:colonRange.location];
|
|
||||||
}
|
|
||||||
return methodName;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (instancetype)initWithReactMethodName:(NSString *)reactMethodName
|
- (instancetype)initWithReactMethodName:(NSString *)reactMethodName
|
||||||
objCMethodName:(NSString *)objCMethodName
|
objCMethodName:(NSString *)objCMethodName
|
||||||
JSMethodName:(NSString *)JSMethodName
|
JSMethodName:(NSString *)JSMethodName
|
||||||
{
|
{
|
||||||
if ((self = [super init])) {
|
if ((self = [super init])) {
|
||||||
_methodName = reactMethodName;
|
|
||||||
NSArray *parts = [[reactMethodName substringWithRange:(NSRange){2, reactMethodName.length - 3}] componentsSeparatedByString:@" "];
|
NSArray *parts = [[reactMethodName substringWithRange:(NSRange){2, reactMethodName.length - 3}] componentsSeparatedByString:@" "];
|
||||||
|
|
||||||
// Parse class and method
|
// Parse class and method
|
||||||
@ -277,12 +266,16 @@ static NSString *RCTStringUpToFirstArgument(NSString *methodName)
|
|||||||
_moduleClassName = [_moduleClassName substringToIndex:categoryRange.location];
|
_moduleClassName = [_moduleClassName substringToIndex:categoryRange.location];
|
||||||
}
|
}
|
||||||
|
|
||||||
NSArray *argumentNames = nil;
|
|
||||||
if ([parts[1] hasPrefix:@"__rct_export__"]) {
|
|
||||||
// New format
|
|
||||||
NSString *selectorString = [parts[1] substringFromIndex:14];
|
NSString *selectorString = [parts[1] substringFromIndex:14];
|
||||||
_selector = NSSelectorFromString(selectorString);
|
_selector = NSSelectorFromString(selectorString);
|
||||||
_JSMethodName = JSMethodName ?: RCTStringUpToFirstArgument(selectorString);
|
_JSMethodName = JSMethodName ?: ({
|
||||||
|
NSString *methodName = selectorString;
|
||||||
|
NSRange colonRange = [methodName rangeOfString:@":"];
|
||||||
|
if (colonRange.length) {
|
||||||
|
methodName = [methodName substringToIndex:colonRange.location];
|
||||||
|
}
|
||||||
|
methodName;
|
||||||
|
});
|
||||||
|
|
||||||
static NSRegularExpression *regExp;
|
static NSRegularExpression *regExp;
|
||||||
if (!regExp) {
|
if (!regExp) {
|
||||||
@ -293,20 +286,13 @@ static NSString *RCTStringUpToFirstArgument(NSString *methodName)
|
|||||||
regExp = [[NSRegularExpression alloc] initWithPattern:pattern options:0 error:NULL];
|
regExp = [[NSRegularExpression alloc] initWithPattern:pattern options:0 error:NULL];
|
||||||
}
|
}
|
||||||
|
|
||||||
argumentNames = [NSMutableArray array];
|
NSMutableArray *argumentNames = [NSMutableArray array];
|
||||||
[regExp enumerateMatchesInString:objCMethodName options:0 range:NSMakeRange(0, objCMethodName.length) usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {
|
[regExp enumerateMatchesInString:objCMethodName options:0 range:NSMakeRange(0, objCMethodName.length) usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {
|
||||||
NSString *argumentName = [objCMethodName substringWithRange:[result rangeAtIndex:1]];
|
NSString *argumentName = [objCMethodName substringWithRange:[result rangeAtIndex:1]];
|
||||||
[(NSMutableArray *)argumentNames addObject:argumentName];
|
[argumentNames addObject:argumentName];
|
||||||
}];
|
}];
|
||||||
} else {
|
|
||||||
// Old format
|
|
||||||
NSString *selectorString = parts[1];
|
|
||||||
_selector = NSSelectorFromString(selectorString);
|
|
||||||
_JSMethodName = JSMethodName ?: RCTStringUpToFirstArgument(selectorString);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extract class and method details
|
// Extract class and method details
|
||||||
_isClassMethod = [reactMethodName characterAtIndex:0] == '+';
|
|
||||||
_moduleClass = NSClassFromString(_moduleClassName);
|
_moduleClass = NSClassFromString(_moduleClassName);
|
||||||
|
|
||||||
if (RCT_DEBUG) {
|
if (RCT_DEBUG) {
|
||||||
@ -318,9 +304,7 @@ static NSString *RCTStringUpToFirstArgument(NSString *methodName)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get method signature
|
// Get method signature
|
||||||
_methodSignature = _isClassMethod ?
|
_methodSignature = [_moduleClass instanceMethodSignatureForSelector:_selector];
|
||||||
[_moduleClass methodSignatureForSelector:_selector] :
|
|
||||||
[_moduleClass instanceMethodSignatureForSelector:_selector];
|
|
||||||
|
|
||||||
// Process arguments
|
// Process arguments
|
||||||
NSUInteger numberOfArguments = _methodSignature.numberOfArguments;
|
NSUInteger numberOfArguments = _methodSignature.numberOfArguments;
|
||||||
@ -363,12 +347,9 @@ static NSString *RCTStringUpToFirstArgument(NSString *methodName)
|
|||||||
for (NSUInteger i = 2; i < numberOfArguments; i++) {
|
for (NSUInteger i = 2; i < numberOfArguments; i++) {
|
||||||
const char *argumentType = [_methodSignature getArgumentTypeAtIndex:i];
|
const char *argumentType = [_methodSignature getArgumentTypeAtIndex:i];
|
||||||
|
|
||||||
BOOL useFallback = YES;
|
|
||||||
if (argumentNames) {
|
|
||||||
NSString *argumentName = argumentNames[i - 2];
|
NSString *argumentName = argumentNames[i - 2];
|
||||||
SEL selector = NSSelectorFromString([argumentName stringByAppendingString:@":"]);
|
SEL selector = NSSelectorFromString([argumentName stringByAppendingString:@":"]);
|
||||||
if ([RCTConvert respondsToSelector:selector]) {
|
if ([RCTConvert respondsToSelector:selector]) {
|
||||||
useFallback = NO;
|
|
||||||
switch (argumentType[0]) {
|
switch (argumentType[0]) {
|
||||||
|
|
||||||
#define RCT_CONVERT_CASE(_value, _type) \
|
#define RCT_CONVERT_CASE(_value, _type) \
|
||||||
@ -419,63 +400,11 @@ static NSString *RCTStringUpToFirstArgument(NSString *methodName)
|
|||||||
}
|
}
|
||||||
} else if ([argumentName isEqualToString:@"RCTResponseSenderBlock"]) {
|
} else if ([argumentName isEqualToString:@"RCTResponseSenderBlock"]) {
|
||||||
addBlockArgument();
|
addBlockArgument();
|
||||||
useFallback = NO;
|
} else {
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (useFallback) {
|
// Unknown argument type
|
||||||
switch (argumentType[0]) {
|
RCTLogError(@"Unknown argument type '%@' in method %@. Extend RCTConvert"
|
||||||
|
" to support this type.", argumentName, [self methodName]);
|
||||||
#define RCT_CASE(_value, _class, _logic) \
|
|
||||||
case _value: { \
|
|
||||||
RCT_ARG_BLOCK( \
|
|
||||||
if (RCT_DEBUG && json && ![json isKindOfClass:[_class class]]) { \
|
|
||||||
RCTLogError(@"Argument %tu (%@) of %@.%@ should be of type %@", index, \
|
|
||||||
json, RCTBridgeModuleNameForClass(_moduleClass), _JSMethodName, [_class class]); \
|
|
||||||
return; \
|
|
||||||
} \
|
|
||||||
_logic \
|
|
||||||
) \
|
|
||||||
break; \
|
|
||||||
}
|
|
||||||
|
|
||||||
RCT_CASE(':', NSString, SEL value = NSSelectorFromString(json); )
|
|
||||||
RCT_CASE('*', NSString, const char *value = [json UTF8String]; )
|
|
||||||
|
|
||||||
#define RCT_SIMPLE_CASE(_value, _type, _selector) \
|
|
||||||
case _value: { \
|
|
||||||
RCT_ARG_BLOCK( \
|
|
||||||
if (RCT_DEBUG && json && ![json respondsToSelector:@selector(_selector)]) { \
|
|
||||||
RCTLogError(@"Argument %tu (%@) of %@.%@ does not respond to selector: %@", \
|
|
||||||
index, json, RCTBridgeModuleNameForClass(_moduleClass), _JSMethodName, @#_selector); \
|
|
||||||
return; \
|
|
||||||
} \
|
|
||||||
_type value = [json _selector]; \
|
|
||||||
) \
|
|
||||||
break; \
|
|
||||||
}
|
|
||||||
|
|
||||||
RCT_SIMPLE_CASE('c', char, charValue)
|
|
||||||
RCT_SIMPLE_CASE('C', unsigned char, unsignedCharValue)
|
|
||||||
RCT_SIMPLE_CASE('s', short, shortValue)
|
|
||||||
RCT_SIMPLE_CASE('S', unsigned short, unsignedShortValue)
|
|
||||||
RCT_SIMPLE_CASE('i', int, intValue)
|
|
||||||
RCT_SIMPLE_CASE('I', unsigned int, unsignedIntValue)
|
|
||||||
RCT_SIMPLE_CASE('l', long, longValue)
|
|
||||||
RCT_SIMPLE_CASE('L', unsigned long, unsignedLongValue)
|
|
||||||
RCT_SIMPLE_CASE('q', long long, longLongValue)
|
|
||||||
RCT_SIMPLE_CASE('Q', unsigned long long, unsignedLongLongValue)
|
|
||||||
RCT_SIMPLE_CASE('f', float, floatValue)
|
|
||||||
RCT_SIMPLE_CASE('d', double, doubleValue)
|
|
||||||
RCT_SIMPLE_CASE('B', BOOL, boolValue)
|
|
||||||
|
|
||||||
case '{':
|
|
||||||
RCTLogMustFix(@"Cannot convert JSON to struct %s", argumentType);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
defaultCase(argumentType);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -494,7 +423,7 @@ static NSString *RCTStringUpToFirstArgument(NSString *methodName)
|
|||||||
|
|
||||||
// Sanity check
|
// Sanity check
|
||||||
RCTAssert([module class] == _moduleClass, @"Attempted to invoke method \
|
RCTAssert([module class] == _moduleClass, @"Attempted to invoke method \
|
||||||
%@ on a module of class %@", _methodName, [module class]);
|
%@ on a module of class %@", [self methodName], [module class]);
|
||||||
|
|
||||||
// Safety check
|
// Safety check
|
||||||
if (arguments.count != _argumentBlocks.count) {
|
if (arguments.count != _argumentBlocks.count) {
|
||||||
@ -520,12 +449,19 @@ static NSString *RCTStringUpToFirstArgument(NSString *methodName)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Invoke method
|
// Invoke method
|
||||||
[invocation invokeWithTarget:_isClassMethod ? [module class] : module];
|
[invocation invokeWithTarget:module];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString *)methodName
|
||||||
|
{
|
||||||
|
return [NSString stringWithFormat:@"-[%@ %@]", _moduleClass,
|
||||||
|
NSStringFromSelector(_selector)];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSString *)description
|
- (NSString *)description
|
||||||
{
|
{
|
||||||
return [NSString stringWithFormat:@"<%@: %p; exports %@ as %@;>", NSStringFromClass(self.class), self, _methodName, _JSMethodName];
|
return [NSString stringWithFormat:@"<%@: %p; exports %@ as %@();>",
|
||||||
|
[self class], self, [self methodName], _JSMethodName];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@ -562,19 +498,10 @@ static RCTSparseArray *RCTExportedMethodsByModuleID(void)
|
|||||||
const char **entries = (const char **)(mach_header + addr);
|
const char **entries = (const char **)(mach_header + addr);
|
||||||
|
|
||||||
// Create method
|
// Create method
|
||||||
RCTModuleMethod *moduleMethod;
|
RCTModuleMethod *moduleMethod =
|
||||||
if (entries[2] == NULL) {
|
[[RCTModuleMethod alloc] initWithReactMethodName:@(entries[0])
|
||||||
|
objCMethodName:@(entries[1])
|
||||||
// Legacy support for RCT_EXPORT()
|
|
||||||
moduleMethod = [[RCTModuleMethod alloc] initWithReactMethodName:@(entries[0])
|
|
||||||
objCMethodName:@(entries[0])
|
|
||||||
JSMethodName:strlen(entries[1]) ? @(entries[1]) : nil];
|
|
||||||
} else {
|
|
||||||
moduleMethod = [[RCTModuleMethod alloc] initWithReactMethodName:@(entries[0])
|
|
||||||
objCMethodName:strlen(entries[1]) ? @(entries[1]) : nil
|
|
||||||
JSMethodName:strlen(entries[2]) ? @(entries[2]) : nil];
|
JSMethodName:strlen(entries[2]) ? @(entries[2]) : nil];
|
||||||
}
|
|
||||||
|
|
||||||
// Cache method
|
// Cache method
|
||||||
NSArray *methods = methodsByModuleClassName[moduleMethod.moduleClassName];
|
NSArray *methods = methodsByModuleClassName[moduleMethod.moduleClassName];
|
||||||
methodsByModuleClassName[moduleMethod.moduleClassName] =
|
methodsByModuleClassName[moduleMethod.moduleClassName] =
|
||||||
@ -1313,7 +1240,12 @@ RCT_INNER_BRIDGE_ONLY(_invokeAndProcessModule:(NSString *)module method:(NSStrin
|
|||||||
|
|
||||||
#pragma mark - Payload Generation
|
#pragma mark - Payload Generation
|
||||||
|
|
||||||
- (void)dispatchBlock:(dispatch_block_t)block forModule:(NSNumber *)moduleID
|
- (void)dispatchBlock:(dispatch_block_t)block forModule:(id<RCTBridgeModule>)module
|
||||||
|
{
|
||||||
|
[self dispatchBlock:block forModuleID:RCTModuleIDsByName[RCTBridgeModuleNameForClass([module class])]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)dispatchBlock:(dispatch_block_t)block forModuleID:(NSNumber *)moduleID
|
||||||
{
|
{
|
||||||
RCTAssertJSThread();
|
RCTAssertJSThread();
|
||||||
|
|
||||||
@ -1458,7 +1390,7 @@ RCT_INNER_BRIDGE_ONLY(_invokeAndProcessModule:(NSString *)module method:(NSStrin
|
|||||||
if ([module respondsToSelector:@selector(batchDidComplete)]) {
|
if ([module respondsToSelector:@selector(batchDidComplete)]) {
|
||||||
[self dispatchBlock:^{
|
[self dispatchBlock:^{
|
||||||
[module batchDidComplete];
|
[module batchDidComplete];
|
||||||
} forModule:moduleID];
|
} forModuleID:moduleID];
|
||||||
}
|
}
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
@ -1526,7 +1458,7 @@ RCT_INNER_BRIDGE_ONLY(_invokeAndProcessModule:(NSString *)module method:(NSStrin
|
|||||||
@"selector": NSStringFromSelector(method.selector),
|
@"selector": NSStringFromSelector(method.selector),
|
||||||
@"args": RCTJSONStringify(params ?: [NSNull null], NULL),
|
@"args": RCTJSONStringify(params ?: [NSNull null], NULL),
|
||||||
});
|
});
|
||||||
} forModule:@(moduleID)];
|
} forModuleID:@(moduleID)];
|
||||||
|
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
@ -1546,7 +1478,7 @@ RCT_INNER_BRIDGE_ONLY(_invokeAndProcessModule:(NSString *)module method:(NSStrin
|
|||||||
RCTProfileBeginEvent();
|
RCTProfileBeginEvent();
|
||||||
[observer didUpdateFrame:frameUpdate];
|
[observer didUpdateFrame:frameUpdate];
|
||||||
RCTProfileEndEvent(name, @"objc_call,fps", nil);
|
RCTProfileEndEvent(name, @"objc_call,fps", nil);
|
||||||
} forModule:RCTModuleIDsByName[RCTBridgeModuleNameForClass([observer class])]];
|
} forModule:(id<RCTBridgeModule>)observer];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1598,14 +1530,17 @@ RCT_INNER_BRIDGE_ONLY(_invokeAndProcessModule:(NSString *)module method:(NSStrin
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
RCTProfileInit();
|
[_javaScriptExecutor executeBlockOnJavaScriptQueue:^{
|
||||||
|
RCTProfileInit(self);
|
||||||
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)stopProfiling
|
- (void)stopProfiling
|
||||||
{
|
{
|
||||||
RCTAssertMainThread();
|
RCTAssertMainThread();
|
||||||
|
|
||||||
NSString *log = RCTProfileEnd();
|
[_javaScriptExecutor executeBlockOnJavaScriptQueue:^{
|
||||||
|
NSString *log = RCTProfileEnd(self);
|
||||||
NSURL *bundleURL = _parentBridge.bundleURL;
|
NSURL *bundleURL = _parentBridge.bundleURL;
|
||||||
NSString *URLString = [NSString stringWithFormat:@"%@://%@:%@/profile", bundleURL.scheme, bundleURL.host, bundleURL.port];
|
NSString *URLString = [NSString stringWithFormat:@"%@://%@:%@/profile", bundleURL.scheme, bundleURL.host, bundleURL.port];
|
||||||
NSURL *URL = [NSURL URLWithString:URLString];
|
NSURL *URL = [NSURL URLWithString:URLString];
|
||||||
@ -1620,6 +1555,7 @@ RCT_INNER_BRIDGE_ONLY(_invokeAndProcessModule:(NSString *)module method:(NSStrin
|
|||||||
}
|
}
|
||||||
}];
|
}];
|
||||||
[task resume];
|
[task resume];
|
||||||
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
@ -145,15 +145,6 @@ extern const dispatch_queue_t RCTJSThread;
|
|||||||
static const char *__rct_export_entry__[] = { __func__, #method, #js_name }; \
|
static const char *__rct_export_entry__[] = { __func__, #method, #js_name }; \
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Deprecated, do not use.
|
|
||||||
*/
|
|
||||||
#define RCT_EXPORT(js_name) \
|
|
||||||
_Pragma("message(\"RCT_EXPORT is deprecated. Use RCT_EXPORT_METHOD instead.\")") \
|
|
||||||
__attribute__((used, section("__DATA,RCTExport"))) \
|
|
||||||
__attribute__((__aligned__(1))) \
|
|
||||||
static const char *__rct_export_entry__[] = { __func__, #js_name, NULL }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The queue that will be used to call all exported methods. If omitted, this
|
* The queue that will be used to call all exported methods. If omitted, this
|
||||||
* will call on the default background queue, which is avoids blocking the main
|
* will call on the default background queue, which is avoids blocking the main
|
||||||
|
@ -23,6 +23,8 @@
|
|||||||
*/
|
*/
|
||||||
@interface RCTConvert : NSObject
|
@interface RCTConvert : NSObject
|
||||||
|
|
||||||
|
+ (id)id:(id)json;
|
||||||
|
|
||||||
+ (BOOL)BOOL:(id)json;
|
+ (BOOL)BOOL:(id)json;
|
||||||
+ (double)double:(id)json;
|
+ (double)double:(id)json;
|
||||||
+ (float)float:(id)json;
|
+ (float)float:(id)json;
|
||||||
@ -52,7 +54,6 @@
|
|||||||
+ (NSWritingDirection)NSWritingDirection:(id)json;
|
+ (NSWritingDirection)NSWritingDirection:(id)json;
|
||||||
+ (UITextAutocapitalizationType)UITextAutocapitalizationType:(id)json;
|
+ (UITextAutocapitalizationType)UITextAutocapitalizationType:(id)json;
|
||||||
+ (UITextFieldViewMode)UITextFieldViewMode:(id)json;
|
+ (UITextFieldViewMode)UITextFieldViewMode:(id)json;
|
||||||
+ (UIScrollViewKeyboardDismissMode)UIScrollViewKeyboardDismissMode:(id)json;
|
|
||||||
+ (UIKeyboardType)UIKeyboardType:(id)json;
|
+ (UIKeyboardType)UIKeyboardType:(id)json;
|
||||||
+ (UIReturnKeyType)UIReturnKeyType:(id)json;
|
+ (UIReturnKeyType)UIReturnKeyType:(id)json;
|
||||||
|
|
||||||
|
@ -21,6 +21,8 @@ void RCTLogConvertError(id json, const char *type)
|
|||||||
json, [json classForCoder], type);
|
json, [json classForCoder], type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RCT_CONVERTER(id, id, self)
|
||||||
|
|
||||||
RCT_CONVERTER(BOOL, BOOL, boolValue)
|
RCT_CONVERTER(BOOL, BOOL, boolValue)
|
||||||
RCT_NUMBER_CONVERTER(double, doubleValue)
|
RCT_NUMBER_CONVERTER(double, doubleValue)
|
||||||
RCT_NUMBER_CONVERTER(float, floatValue)
|
RCT_NUMBER_CONVERTER(float, floatValue)
|
||||||
@ -219,12 +221,6 @@ RCT_ENUM_CONVERTER(UITextFieldViewMode, (@{
|
|||||||
@"always": @(UITextFieldViewModeAlways),
|
@"always": @(UITextFieldViewModeAlways),
|
||||||
}), UITextFieldViewModeNever, integerValue)
|
}), UITextFieldViewModeNever, integerValue)
|
||||||
|
|
||||||
RCT_ENUM_CONVERTER(UIScrollViewKeyboardDismissMode, (@{
|
|
||||||
@"none": @(UIScrollViewKeyboardDismissModeNone),
|
|
||||||
@"on-drag": @(UIScrollViewKeyboardDismissModeOnDrag),
|
|
||||||
@"interactive": @(UIScrollViewKeyboardDismissModeInteractive),
|
|
||||||
}), UIScrollViewKeyboardDismissModeNone, integerValue)
|
|
||||||
|
|
||||||
RCT_ENUM_CONVERTER(UIKeyboardType, (@{
|
RCT_ENUM_CONVERTER(UIKeyboardType, (@{
|
||||||
@"default": @(UIKeyboardTypeDefault),
|
@"default": @(UIKeyboardTypeDefault),
|
||||||
@"ascii-capable": @(UIKeyboardTypeASCIICapable),
|
@"ascii-capable": @(UIKeyboardTypeASCIICapable),
|
||||||
@ -237,6 +233,8 @@ RCT_ENUM_CONVERTER(UIKeyboardType, (@{
|
|||||||
@"decimal-pad": @(UIKeyboardTypeDecimalPad),
|
@"decimal-pad": @(UIKeyboardTypeDecimalPad),
|
||||||
@"twitter": @(UIKeyboardTypeTwitter),
|
@"twitter": @(UIKeyboardTypeTwitter),
|
||||||
@"web-search": @(UIKeyboardTypeWebSearch),
|
@"web-search": @(UIKeyboardTypeWebSearch),
|
||||||
|
// Added for Android compatibility
|
||||||
|
@"numeric": @(UIKeyboardTypeDecimalPad),
|
||||||
}), UIKeyboardTypeDefault, integerValue)
|
}), UIKeyboardTypeDefault, integerValue)
|
||||||
|
|
||||||
RCT_ENUM_CONVERTER(UIReturnKeyType, (@{
|
RCT_ENUM_CONVERTER(UIReturnKeyType, (@{
|
||||||
@ -267,7 +265,11 @@ RCT_ENUM_CONVERTER(UIViewContentMode, (@{
|
|||||||
@"top-right": @(UIViewContentModeTopRight),
|
@"top-right": @(UIViewContentModeTopRight),
|
||||||
@"bottom-left": @(UIViewContentModeBottomLeft),
|
@"bottom-left": @(UIViewContentModeBottomLeft),
|
||||||
@"bottom-right": @(UIViewContentModeBottomRight),
|
@"bottom-right": @(UIViewContentModeBottomRight),
|
||||||
}), UIViewContentModeScaleToFill, integerValue)
|
// Cross-platform values
|
||||||
|
@"cover": @(UIViewContentModeScaleAspectFill),
|
||||||
|
@"contain": @(UIViewContentModeScaleAspectFit),
|
||||||
|
@"stretch": @(UIViewContentModeScaleToFill),
|
||||||
|
}), UIViewContentModeScaleAspectFill, integerValue)
|
||||||
|
|
||||||
RCT_ENUM_CONVERTER(UIBarStyle, (@{
|
RCT_ENUM_CONVERTER(UIBarStyle, (@{
|
||||||
@"default": @(UIBarStyleDefault),
|
@"default": @(UIBarStyleDefault),
|
||||||
|
@ -51,6 +51,12 @@
|
|||||||
*/
|
*/
|
||||||
- (void)reload;
|
- (void)reload;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add custom item to the development menu. The handler will be called
|
||||||
|
* when user selects the item.
|
||||||
|
*/
|
||||||
|
- (void)addItem:(NSString *)title handler:(dispatch_block_t)handler;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -43,6 +43,28 @@ static NSString *const RCTDevMenuSettingsKey = @"RCTDevMenu";
|
|||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
@interface RCTDevMenuItem : NSObject
|
||||||
|
|
||||||
|
@property (nonatomic, copy) NSString *title;
|
||||||
|
@property (nonatomic, copy) dispatch_block_t handler;
|
||||||
|
|
||||||
|
- (instancetype)initWithTitle:(NSString *)title handler:(dispatch_block_t)handler;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation RCTDevMenuItem
|
||||||
|
|
||||||
|
- (instancetype)initWithTitle:(NSString *)title handler:(dispatch_block_t)handler
|
||||||
|
{
|
||||||
|
if (self = [super init]) {
|
||||||
|
self.title = title;
|
||||||
|
self.handler = handler;
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
@interface RCTDevMenu () <RCTBridgeModule, UIActionSheetDelegate>
|
@interface RCTDevMenu () <RCTBridgeModule, UIActionSheetDelegate>
|
||||||
|
|
||||||
@property (nonatomic, strong) Class executorClass;
|
@property (nonatomic, strong) Class executorClass;
|
||||||
@ -57,6 +79,8 @@ static NSString *const RCTDevMenuSettingsKey = @"RCTDevMenu";
|
|||||||
NSURLSessionDataTask *_updateTask;
|
NSURLSessionDataTask *_updateTask;
|
||||||
NSURL *_liveReloadURL;
|
NSURL *_liveReloadURL;
|
||||||
BOOL _jsLoaded;
|
BOOL _jsLoaded;
|
||||||
|
NSArray *_presentedItems;
|
||||||
|
NSMutableArray *_extraMenuItems;
|
||||||
}
|
}
|
||||||
|
|
||||||
@synthesize bridge = _bridge;
|
@synthesize bridge = _bridge;
|
||||||
@ -94,6 +118,7 @@ RCT_EXPORT_MODULE()
|
|||||||
|
|
||||||
_defaults = [NSUserDefaults standardUserDefaults];
|
_defaults = [NSUserDefaults standardUserDefaults];
|
||||||
_settings = [[NSMutableDictionary alloc] init];
|
_settings = [[NSMutableDictionary alloc] init];
|
||||||
|
_extraMenuItems = [NSMutableArray array];
|
||||||
|
|
||||||
// Delay setup until after Bridge init
|
// Delay setup until after Bridge init
|
||||||
[self settingsDidChange];
|
[self settingsDidChange];
|
||||||
@ -110,6 +135,13 @@ RCT_EXPORT_MODULE()
|
|||||||
[weakSelf toggle];
|
[weakSelf toggle];
|
||||||
}];
|
}];
|
||||||
|
|
||||||
|
// Toggle element inspector
|
||||||
|
[commands registerKeyCommandWithInput:@"i"
|
||||||
|
modifierFlags:UIKeyModifierCommand
|
||||||
|
action:^(UIKeyCommand *command) {
|
||||||
|
[_bridge.eventDispatcher sendDeviceEventWithName:@"toggleElementInspector" body:nil];
|
||||||
|
}];
|
||||||
|
|
||||||
// Reload in normal mode
|
// Reload in normal mode
|
||||||
[commands registerKeyCommandWithInput:@"n"
|
[commands registerKeyCommandWithInput:@"n"
|
||||||
modifierFlags:UIKeyModifierCommand
|
modifierFlags:UIKeyModifierCommand
|
||||||
@ -225,32 +257,82 @@ RCT_EXPORT_MODULE()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)addItem:(NSString *)title handler:(dispatch_block_t)handler
|
||||||
|
{
|
||||||
|
[_extraMenuItems addObject:[[RCTDevMenuItem alloc] initWithTitle:title handler:handler]];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSArray *)menuItems
|
||||||
|
{
|
||||||
|
NSMutableArray *items = [NSMutableArray array];
|
||||||
|
|
||||||
|
[items addObject:[[RCTDevMenuItem alloc] initWithTitle:@"Reload" handler:^{
|
||||||
|
[self reload];
|
||||||
|
}]];
|
||||||
|
|
||||||
|
Class chromeExecutorClass = NSClassFromString(@"RCTWebSocketExecutor");
|
||||||
|
if (!chromeExecutorClass) {
|
||||||
|
[items addObject:[[RCTDevMenuItem alloc] initWithTitle:@"Chrome Debugger Unavailable" handler:^{
|
||||||
|
[[[UIAlertView alloc] initWithTitle:@"Chrome Debugger Unavailable"
|
||||||
|
message:@"You need to include the RCTWebSocket library to enable Chrome debugging"
|
||||||
|
delegate:nil
|
||||||
|
cancelButtonTitle:@"OK"
|
||||||
|
otherButtonTitles:nil] show];
|
||||||
|
}]];
|
||||||
|
} else {
|
||||||
|
BOOL isDebuggingInChrome = _executorClass && _executorClass == chromeExecutorClass;
|
||||||
|
NSString *debugTitleChrome = isDebuggingInChrome ? @"Disable Chrome Debugging" : @"Debug in Chrome";
|
||||||
|
[items addObject:[[RCTDevMenuItem alloc] initWithTitle:debugTitleChrome handler:^{
|
||||||
|
self.executorClass = isDebuggingInChrome ? Nil : chromeExecutorClass;
|
||||||
|
}]];
|
||||||
|
}
|
||||||
|
|
||||||
|
Class safariExecutorClass = NSClassFromString(@"RCTWebViewExecutor");
|
||||||
|
BOOL isDebuggingInSafari = _executorClass && _executorClass == safariExecutorClass;
|
||||||
|
NSString *debugTitleSafari = isDebuggingInSafari ? @"Disable Safari Debugging" : @"Debug in Safari";
|
||||||
|
[items addObject:[[RCTDevMenuItem alloc] initWithTitle:debugTitleSafari handler:^{
|
||||||
|
self.executorClass = isDebuggingInSafari ? Nil : safariExecutorClass;
|
||||||
|
}]];
|
||||||
|
|
||||||
|
NSString *fpsMonitor = _showFPS ? @"Hide FPS Monitor" : @"Show FPS Monitor";
|
||||||
|
[items addObject:[[RCTDevMenuItem alloc] initWithTitle:fpsMonitor handler:^{
|
||||||
|
self.showFPS = !_showFPS;
|
||||||
|
}]];
|
||||||
|
|
||||||
|
[items addObject:[[RCTDevMenuItem alloc] initWithTitle:@"Inspect Element" handler:^{
|
||||||
|
[_bridge.eventDispatcher sendDeviceEventWithName:@"toggleElementInspector" body:nil];
|
||||||
|
}]];
|
||||||
|
|
||||||
|
if (_liveReloadURL) {
|
||||||
|
NSString *liveReloadTitle = _liveReloadEnabled ? @"Disable Live Reload" : @"Enable Live Reload";
|
||||||
|
[items addObject:[[RCTDevMenuItem alloc] initWithTitle:liveReloadTitle handler:^{
|
||||||
|
self.liveReloadEnabled = !_liveReloadEnabled;
|
||||||
|
}]];
|
||||||
|
|
||||||
|
NSString *profilingTitle = RCTProfileIsProfiling() ? @"Stop Profiling" : @"Start Profiling";
|
||||||
|
[items addObject:[[RCTDevMenuItem alloc] initWithTitle:profilingTitle handler:^{
|
||||||
|
self.profilingEnabled = !_profilingEnabled;
|
||||||
|
}]];
|
||||||
|
}
|
||||||
|
|
||||||
|
[items addObjectsFromArray:_extraMenuItems];
|
||||||
|
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
RCT_EXPORT_METHOD(show)
|
RCT_EXPORT_METHOD(show)
|
||||||
{
|
{
|
||||||
if (_actionSheet || !_bridge) {
|
if (_actionSheet || !_bridge) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
NSString *debugTitleChrome = _executorClass && _executorClass == NSClassFromString(@"RCTWebSocketExecutor") ? @"Disable Chrome Debugging" : @"Debug in Chrome";
|
UIActionSheet *actionSheet = [[UIActionSheet alloc] init];
|
||||||
NSString *debugTitleSafari = _executorClass && _executorClass == NSClassFromString(@"RCTWebViewExecutor") ? @"Disable Safari Debugging" : @"Debug in Safari";
|
actionSheet.title = @"React Native: Development";
|
||||||
NSString *fpsMonitor = _showFPS ? @"Hide FPS Monitor" : @"Show FPS Monitor";
|
actionSheet.delegate = self;
|
||||||
|
|
||||||
UIActionSheet *actionSheet =
|
NSArray *items = [self menuItems];
|
||||||
[[UIActionSheet alloc] initWithTitle:@"React Native: Development"
|
for (RCTDevMenuItem *item in items) {
|
||||||
delegate:self
|
[actionSheet addButtonWithTitle:item.title];
|
||||||
cancelButtonTitle:nil
|
|
||||||
destructiveButtonTitle:nil
|
|
||||||
otherButtonTitles:@"Reload", debugTitleChrome, debugTitleSafari, fpsMonitor, nil];
|
|
||||||
|
|
||||||
[actionSheet addButtonWithTitle:@"Inspect Element"];
|
|
||||||
|
|
||||||
if (_liveReloadURL) {
|
|
||||||
|
|
||||||
NSString *liveReloadTitle = _liveReloadEnabled ? @"Disable Live Reload" : @"Enable Live Reload";
|
|
||||||
NSString *profilingTitle = RCTProfileIsProfiling() ? @"Stop Profiling" : @"Start Profiling";
|
|
||||||
|
|
||||||
[actionSheet addButtonWithTitle:liveReloadTitle];
|
|
||||||
[actionSheet addButtonWithTitle:profilingTitle];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[actionSheet addButtonWithTitle:@"Cancel"];
|
[actionSheet addButtonWithTitle:@"Cancel"];
|
||||||
@ -259,13 +341,7 @@ RCT_EXPORT_METHOD(show)
|
|||||||
actionSheet.actionSheetStyle = UIBarStyleBlack;
|
actionSheet.actionSheetStyle = UIBarStyleBlack;
|
||||||
[actionSheet showInView:[UIApplication sharedApplication].keyWindow.rootViewController.view];
|
[actionSheet showInView:[UIApplication sharedApplication].keyWindow.rootViewController.view];
|
||||||
_actionSheet = actionSheet;
|
_actionSheet = actionSheet;
|
||||||
}
|
_presentedItems = items;
|
||||||
|
|
||||||
RCT_EXPORT_METHOD(reload)
|
|
||||||
{
|
|
||||||
_jsLoaded = NO;
|
|
||||||
_liveReloadURL = nil;
|
|
||||||
[_bridge reload];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
|
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
|
||||||
@ -275,48 +351,16 @@ RCT_EXPORT_METHOD(reload)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (buttonIndex) {
|
RCTDevMenuItem *item = _presentedItems[buttonIndex];
|
||||||
case 0: {
|
item.handler();
|
||||||
[self reload];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 1: {
|
|
||||||
Class cls = NSClassFromString(@"RCTWebSocketExecutor");
|
|
||||||
if (!cls) {
|
|
||||||
[[[UIAlertView alloc] initWithTitle:@"Chrome Debugger Unavailable"
|
|
||||||
message:@"You need to include the RCTWebSocket library to enable Chrome debugging"
|
|
||||||
delegate:nil
|
|
||||||
cancelButtonTitle:@"OK"
|
|
||||||
otherButtonTitles:nil] show];
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
self.executorClass = (_executorClass == cls) ? Nil : cls;
|
|
||||||
break;
|
RCT_EXPORT_METHOD(reload)
|
||||||
}
|
{
|
||||||
case 2: {
|
_jsLoaded = NO;
|
||||||
Class cls = NSClassFromString(@"RCTWebViewExecutor");
|
_liveReloadURL = nil;
|
||||||
self.executorClass = (_executorClass == cls) ? Nil : cls;
|
[_bridge reload];
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 3: {
|
|
||||||
self.showFPS = !_showFPS;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 4: {
|
|
||||||
[_bridge.eventDispatcher sendDeviceEventWithName:@"toggleElementInspector" body:nil];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 5: {
|
|
||||||
self.liveReloadEnabled = !_liveReloadEnabled;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 6: {
|
|
||||||
self.profilingEnabled = !_profilingEnabled;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setShakeToShow:(BOOL)shakeToShow
|
- (void)setShakeToShow:(BOOL)shakeToShow
|
||||||
@ -438,6 +482,7 @@ RCT_EXPORT_METHOD(reload)
|
|||||||
|
|
||||||
- (void)show {}
|
- (void)show {}
|
||||||
- (void)reload {}
|
- (void)reload {}
|
||||||
|
- (void)addItem:(NSString *)title handler:(dispatch_block_t)handler {}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
@ -25,6 +25,8 @@ NSString *const RCTProfileDidEndProfiling;
|
|||||||
|
|
||||||
#if RCT_DEV
|
#if RCT_DEV
|
||||||
|
|
||||||
|
@class RCTBridge;
|
||||||
|
|
||||||
#define RCTProfileBeginFlowEvent() \
|
#define RCTProfileBeginFlowEvent() \
|
||||||
_Pragma("clang diagnostic push") \
|
_Pragma("clang diagnostic push") \
|
||||||
_Pragma("clang diagnostic ignored \"-Wshadow\"") \
|
_Pragma("clang diagnostic ignored \"-Wshadow\"") \
|
||||||
@ -45,14 +47,14 @@ RCT_EXTERN BOOL RCTProfileIsProfiling(void);
|
|||||||
/**
|
/**
|
||||||
* Start collecting profiling information
|
* Start collecting profiling information
|
||||||
*/
|
*/
|
||||||
RCT_EXTERN void RCTProfileInit(void);
|
RCT_EXTERN void RCTProfileInit(RCTBridge *);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stop profiling and return a JSON string of the collected data - The data
|
* Stop profiling and return a JSON string of the collected data - The data
|
||||||
* returned is compliant with google's trace event format - the format used
|
* returned is compliant with google's trace event format - the format used
|
||||||
* as input to trace-viewer
|
* as input to trace-viewer
|
||||||
*/
|
*/
|
||||||
RCT_EXTERN NSString *RCTProfileEnd(void);
|
RCT_EXTERN NSString *RCTProfileEnd(RCTBridge *);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Collects the initial event information for the event and returns a reference ID
|
* Collects the initial event information for the event and returns a reference ID
|
||||||
|
@ -10,10 +10,13 @@
|
|||||||
#import "RCTProfile.h"
|
#import "RCTProfile.h"
|
||||||
|
|
||||||
#import <mach/mach.h>
|
#import <mach/mach.h>
|
||||||
|
#import <objc/message.h>
|
||||||
|
#import <objc/runtime.h>
|
||||||
|
|
||||||
#import <UIKit/UIKit.h>
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
#import "RCTAssert.h"
|
#import "RCTAssert.h"
|
||||||
|
#import "RCTBridge.h"
|
||||||
#import "RCTDefines.h"
|
#import "RCTDefines.h"
|
||||||
#import "RCTUtils.h"
|
#import "RCTUtils.h"
|
||||||
|
|
||||||
@ -32,6 +35,7 @@ NSDictionary *RCTProfileGetMemoryUsage(void);
|
|||||||
|
|
||||||
NSString const *RCTProfileTraceEvents = @"traceEvents";
|
NSString const *RCTProfileTraceEvents = @"traceEvents";
|
||||||
NSString const *RCTProfileSamples = @"samples";
|
NSString const *RCTProfileSamples = @"samples";
|
||||||
|
NSString *const RCTProfilePrefix = @"rct_profile_";
|
||||||
|
|
||||||
#pragma mark - Variables
|
#pragma mark - Variables
|
||||||
|
|
||||||
@ -92,6 +96,111 @@ NSDictionary *RCTProfileGetMemoryUsage(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma mark - Module hooks
|
||||||
|
|
||||||
|
@interface RCTBridge (Private)
|
||||||
|
|
||||||
|
- (void)dispatchBlock:(dispatch_block_t)block forModule:(id<RCTBridgeModule>)module;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
static const char *RCTProfileProxyClassName(Class);
|
||||||
|
static const char *RCTProfileProxyClassName(Class class)
|
||||||
|
{
|
||||||
|
return [RCTProfilePrefix stringByAppendingString:NSStringFromClass(class)].UTF8String;
|
||||||
|
}
|
||||||
|
|
||||||
|
static SEL RCTProfileProxySelector(SEL);
|
||||||
|
static SEL RCTProfileProxySelector(SEL selector)
|
||||||
|
{
|
||||||
|
NSString *selectorName = NSStringFromSelector(selector);
|
||||||
|
return NSSelectorFromString([RCTProfilePrefix stringByAppendingString:selectorName]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void RCTProfileForwardInvocation(NSObject *, SEL, NSInvocation *);
|
||||||
|
static void RCTProfileForwardInvocation(NSObject *self, SEL cmd, NSInvocation *invocation)
|
||||||
|
{
|
||||||
|
NSString *name = [NSString stringWithFormat:@"-[%@ %@]", NSStringFromClass([self class]), NSStringFromSelector(invocation.selector)];
|
||||||
|
SEL newSel = RCTProfileProxySelector(invocation.selector);
|
||||||
|
|
||||||
|
if ([object_getClass(self) instancesRespondToSelector:newSel]) {
|
||||||
|
invocation.selector = newSel;
|
||||||
|
RCTProfileBeginEvent();
|
||||||
|
[invocation invoke];
|
||||||
|
RCTProfileEndEvent(name, @"objc_call,modules,auto", nil);
|
||||||
|
} else {
|
||||||
|
// Use original selector to don't change error message
|
||||||
|
[self doesNotRecognizeSelector:invocation.selector];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static IMP RCTProfileMsgForward(NSObject *, SEL);
|
||||||
|
static IMP RCTProfileMsgForward(NSObject *self, SEL selector)
|
||||||
|
{
|
||||||
|
IMP imp = _objc_msgForward;
|
||||||
|
#if !defined(__arm64__)
|
||||||
|
NSMethodSignature *signature = [self methodSignatureForSelector:selector];
|
||||||
|
if (signature.methodReturnType[0] == _C_STRUCT_B && signature.methodReturnLength > 8) {
|
||||||
|
imp = _objc_msgForward_stret;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return imp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void RCTProfileHookModules(RCTBridge *);
|
||||||
|
static void RCTProfileHookModules(RCTBridge *bridge)
|
||||||
|
{
|
||||||
|
[bridge.modules enumerateKeysAndObjectsUsingBlock:^(NSString *className, id<RCTBridgeModule> module, BOOL *stop) {
|
||||||
|
[bridge dispatchBlock:^{
|
||||||
|
Class moduleClass = object_getClass(module);
|
||||||
|
Class proxyClass = objc_allocateClassPair(moduleClass, RCTProfileProxyClassName(moduleClass), 0);
|
||||||
|
|
||||||
|
unsigned int methodCount;
|
||||||
|
Method *methods = class_copyMethodList(moduleClass, &methodCount);
|
||||||
|
for (NSUInteger i = 0; i < methodCount; i++) {
|
||||||
|
Method method = methods[i];
|
||||||
|
SEL selector = method_getName(method);
|
||||||
|
if ([NSStringFromSelector(selector) hasPrefix:@"rct"] || [NSObject instancesRespondToSelector:selector]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
IMP originalIMP = method_getImplementation(method);
|
||||||
|
const char *returnType = method_getTypeEncoding(method);
|
||||||
|
class_addMethod(proxyClass, selector, RCTProfileMsgForward(module, selector), returnType);
|
||||||
|
class_addMethod(proxyClass, RCTProfileProxySelector(selector), originalIMP, returnType);
|
||||||
|
}
|
||||||
|
free(methods);
|
||||||
|
|
||||||
|
for (Class cls in @[proxyClass, object_getClass(proxyClass)]) {
|
||||||
|
Method oldImp = class_getInstanceMethod(cls, @selector(class));
|
||||||
|
class_replaceMethod(cls, @selector(class), imp_implementationWithBlock(^{ return moduleClass; }), method_getTypeEncoding(oldImp));
|
||||||
|
}
|
||||||
|
|
||||||
|
IMP originalFwd = class_replaceMethod(moduleClass, @selector(forwardInvocation:), (IMP)RCTProfileForwardInvocation, "v@:@");
|
||||||
|
if (originalFwd != NULL) {
|
||||||
|
class_addMethod(proxyClass, RCTProfileProxySelector(@selector(forwardInvocation:)), originalFwd, "v@:@");
|
||||||
|
}
|
||||||
|
|
||||||
|
objc_registerClassPair(proxyClass);
|
||||||
|
object_setClass(module, proxyClass);
|
||||||
|
} forModule:module];
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
void RCTProfileUnhookModules(RCTBridge *);
|
||||||
|
void RCTProfileUnhookModules(RCTBridge *bridge)
|
||||||
|
{
|
||||||
|
[bridge.modules enumerateKeysAndObjectsUsingBlock:^(NSString *className, id<RCTBridgeModule> module, BOOL *stop) {
|
||||||
|
[bridge dispatchBlock:^{
|
||||||
|
Class proxyClass = object_getClass(module);
|
||||||
|
if (module.class != proxyClass) {
|
||||||
|
object_setClass(module, module.class);
|
||||||
|
objc_disposeClassPair(proxyClass);
|
||||||
|
}
|
||||||
|
} forModule:module];
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#pragma mark - Public Functions
|
#pragma mark - Public Functions
|
||||||
|
|
||||||
BOOL RCTProfileIsProfiling(void)
|
BOOL RCTProfileIsProfiling(void)
|
||||||
@ -102,8 +211,10 @@ BOOL RCTProfileIsProfiling(void)
|
|||||||
return profiling;
|
return profiling;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RCTProfileInit(void)
|
void RCTProfileInit(RCTBridge *bridge)
|
||||||
{
|
{
|
||||||
|
RCTProfileHookModules(bridge);
|
||||||
|
|
||||||
static dispatch_once_t onceToken;
|
static dispatch_once_t onceToken;
|
||||||
dispatch_once(&onceToken, ^{
|
dispatch_once(&onceToken, ^{
|
||||||
_RCTProfileLock = [[NSLock alloc] init];
|
_RCTProfileLock = [[NSLock alloc] init];
|
||||||
@ -121,7 +232,7 @@ void RCTProfileInit(void)
|
|||||||
object:nil];
|
object:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
NSString *RCTProfileEnd(void)
|
NSString *RCTProfileEnd(RCTBridge *bridge)
|
||||||
{
|
{
|
||||||
[[NSNotificationCenter defaultCenter] postNotificationName:RCTProfileDidEndProfiling
|
[[NSNotificationCenter defaultCenter] postNotificationName:RCTProfileDidEndProfiling
|
||||||
object:nil];
|
object:nil];
|
||||||
@ -132,6 +243,9 @@ NSString *RCTProfileEnd(void)
|
|||||||
RCTProfileInfo = nil;
|
RCTProfileInfo = nil;
|
||||||
RCTProfileOngoingEvents = nil;
|
RCTProfileOngoingEvents = nil;
|
||||||
);
|
);
|
||||||
|
|
||||||
|
RCTProfileUnhookModules(bridge);
|
||||||
|
|
||||||
return log;
|
return log;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,11 +85,6 @@
|
|||||||
selector:@selector(dismiss)
|
selector:@selector(dismiss)
|
||||||
name:RCTReloadNotification
|
name:RCTReloadNotification
|
||||||
object:nil];
|
object:nil];
|
||||||
|
|
||||||
[notificationCenter addObserver:self
|
|
||||||
selector:@selector(dismiss)
|
|
||||||
name:RCTJavaScriptDidLoadNotification
|
|
||||||
object:nil];
|
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
@ -36,8 +36,6 @@
|
|||||||
|
|
||||||
BOOL _recordingInteractionTiming;
|
BOOL _recordingInteractionTiming;
|
||||||
CFTimeInterval _mostRecentEnqueueJS;
|
CFTimeInterval _mostRecentEnqueueJS;
|
||||||
NSMutableArray *_pendingTouches;
|
|
||||||
NSMutableArray *_bridgeInteractionTiming;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (instancetype)initWithBridge:(RCTBridge *)bridge
|
- (instancetype)initWithBridge:(RCTBridge *)bridge
|
||||||
@ -52,9 +50,6 @@
|
|||||||
_reactTouches = [[NSMutableArray alloc] init];
|
_reactTouches = [[NSMutableArray alloc] init];
|
||||||
_touchViews = [[NSMutableArray alloc] init];
|
_touchViews = [[NSMutableArray alloc] init];
|
||||||
|
|
||||||
_pendingTouches = [[NSMutableArray alloc] init];
|
|
||||||
_bridgeInteractionTiming = [[NSMutableArray alloc] init];
|
|
||||||
|
|
||||||
// `cancelsTouchesInView` is needed in order to be used as a top level
|
// `cancelsTouchesInView` is needed in order to be used as a top level
|
||||||
// event delegated recognizer. Otherwise, lower-level components not built
|
// event delegated recognizer. Otherwise, lower-level components not built
|
||||||
// using RCT, will fail to recognize gestures.
|
// using RCT, will fail to recognize gestures.
|
||||||
@ -94,11 +89,11 @@ typedef NS_ENUM(NSInteger, RCTTouchEventType) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get new, unique touch id
|
// Get new, unique touch identifier for the react touch
|
||||||
const NSUInteger RCTMaxTouches = 11; // This is the maximum supported by iDevices
|
const NSUInteger RCTMaxTouches = 11; // This is the maximum supported by iDevices
|
||||||
NSInteger touchID = ([_reactTouches.lastObject[@"target"] integerValue] + 1) % RCTMaxTouches;
|
NSInteger touchID = ([_reactTouches.lastObject[@"identifier"] integerValue] + 1) % RCTMaxTouches;
|
||||||
for (NSDictionary *reactTouch in _reactTouches) {
|
for (NSDictionary *reactTouch in _reactTouches) {
|
||||||
NSInteger usedID = [reactTouch[@"target"] integerValue];
|
NSInteger usedID = [reactTouch[@"identifier"] integerValue];
|
||||||
if (usedID == touchID) {
|
if (usedID == touchID) {
|
||||||
// ID has already been used, try next value
|
// ID has already been used, try next value
|
||||||
touchID ++;
|
touchID ++;
|
||||||
|
@ -18,6 +18,8 @@
|
|||||||
// Utility functions for JSON object <-> string serialization/deserialization
|
// Utility functions for JSON object <-> string serialization/deserialization
|
||||||
RCT_EXTERN NSString *RCTJSONStringify(id jsonObject, NSError **error);
|
RCT_EXTERN NSString *RCTJSONStringify(id jsonObject, NSError **error);
|
||||||
RCT_EXTERN id RCTJSONParse(NSString *jsonString, NSError **error);
|
RCT_EXTERN id RCTJSONParse(NSString *jsonString, NSError **error);
|
||||||
|
RCT_EXTERN id RCTJSONParseMutable(NSString *jsonString, NSError **error);
|
||||||
|
RCT_EXTERN id RCTJSONParseWithOptions(NSString *jsonString, NSError **error, NSJSONReadingOptions options);
|
||||||
|
|
||||||
// Strip non JSON-safe values from an object graph
|
// Strip non JSON-safe values from an object graph
|
||||||
RCT_EXTERN id RCTJSONClean(id object);
|
RCT_EXTERN id RCTJSONClean(id object);
|
||||||
|
@ -24,7 +24,7 @@ NSString *RCTJSONStringify(id jsonObject, NSError **error)
|
|||||||
return jsonData ? [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding] : nil;
|
return jsonData ? [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding] : nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
id RCTJSONParse(NSString *jsonString, NSError **error)
|
id RCTJSONParseWithOptions(NSString *jsonString, NSError **error, NSJSONReadingOptions options)
|
||||||
{
|
{
|
||||||
if (!jsonString) {
|
if (!jsonString) {
|
||||||
return nil;
|
return nil;
|
||||||
@ -39,7 +39,15 @@ id RCTJSONParse(NSString *jsonString, NSError **error)
|
|||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingAllowFragments error:error];
|
return [NSJSONSerialization JSONObjectWithData:jsonData options:options error:error];
|
||||||
|
}
|
||||||
|
|
||||||
|
id RCTJSONParse(NSString *jsonString, NSError **error) {
|
||||||
|
return RCTJSONParseWithOptions(jsonString, error, NSJSONReadingAllowFragments);
|
||||||
|
}
|
||||||
|
|
||||||
|
id RCTJSONParseMutable(NSString *jsonString, NSError **error) {
|
||||||
|
return RCTJSONParseWithOptions(jsonString, error, NSJSONReadingMutableContainers|NSJSONReadingMutableLeaves);
|
||||||
}
|
}
|
||||||
|
|
||||||
id RCTJSONClean(id object)
|
id RCTJSONClean(id object)
|
||||||
|
@ -61,6 +61,34 @@ static id RCTReadFile(NSString *filePath, NSString *key, NSDictionary **errorOut
|
|||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Only merges objects - all other types are just clobbered (including arrays)
|
||||||
|
static void RCTMergeRecursive(NSMutableDictionary *destination, NSDictionary *source)
|
||||||
|
{
|
||||||
|
for (NSString *key in source) {
|
||||||
|
id sourceValue = source[key];
|
||||||
|
if ([sourceValue isKindOfClass:[NSDictionary class]]) {
|
||||||
|
id destinationValue = destination[key];
|
||||||
|
NSMutableDictionary *nestedDestination;
|
||||||
|
if ([destinationValue classForCoder] == [NSMutableDictionary class]) {
|
||||||
|
nestedDestination = destinationValue;
|
||||||
|
} else {
|
||||||
|
if ([destinationValue isKindOfClass:[NSDictionary class]]) {
|
||||||
|
// Ideally we wouldn't eagerly copy here...
|
||||||
|
nestedDestination = [destinationValue mutableCopy];
|
||||||
|
} else {
|
||||||
|
destination[key] = [sourceValue copy];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (nestedDestination) {
|
||||||
|
RCTMergeRecursive(nestedDestination, sourceValue);
|
||||||
|
destination[key] = nestedDestination;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
destination[key] = sourceValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#pragma mark - RCTAsyncLocalStorage
|
#pragma mark - RCTAsyncLocalStorage
|
||||||
|
|
||||||
@implementation RCTAsyncLocalStorage
|
@implementation RCTAsyncLocalStorage
|
||||||
@ -135,13 +163,19 @@ RCT_EXPORT_MODULE()
|
|||||||
if (errorOut) {
|
if (errorOut) {
|
||||||
return errorOut;
|
return errorOut;
|
||||||
}
|
}
|
||||||
|
id value = [self _getValueForKey:key errorOut:&errorOut];
|
||||||
|
[result addObject:@[key, value ?: [NSNull null]]]; // Insert null if missing or failure.
|
||||||
|
return errorOut;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString *)_getValueForKey:(NSString *)key errorOut:(NSDictionary **)errorOut
|
||||||
|
{
|
||||||
id value = _manifest[key]; // nil means missing, null means there is a data file, anything else is an inline value.
|
id value = _manifest[key]; // nil means missing, null means there is a data file, anything else is an inline value.
|
||||||
if (value == [NSNull null]) {
|
if (value == [NSNull null]) {
|
||||||
NSString *filePath = [self _filePathForKey:key];
|
NSString *filePath = [self _filePathForKey:key];
|
||||||
value = RCTReadFile(filePath, key, &errorOut);
|
value = RCTReadFile(filePath, key, errorOut);
|
||||||
}
|
}
|
||||||
[result addObject:@[key, value ?: [NSNull null]]]; // Insert null if missing or failure.
|
return value;
|
||||||
return errorOut;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)_writeEntry:(NSArray *)entry
|
- (id)_writeEntry:(NSArray *)entry
|
||||||
@ -198,7 +232,6 @@ RCT_EXPORT_METHOD(multiGet:(NSArray *)keys
|
|||||||
id keyError = [self _appendItemForKey:key toArray:result];
|
id keyError = [self _appendItemForKey:key toArray:result];
|
||||||
RCTAppendError(keyError, &errors);
|
RCTAppendError(keyError, &errors);
|
||||||
}
|
}
|
||||||
[self _writeManifest:&errors];
|
|
||||||
callback(@[errors ?: [NSNull null], result]);
|
callback(@[errors ?: [NSNull null], result]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -221,6 +254,38 @@ RCT_EXPORT_METHOD(multiSet:(NSArray *)kvPairs
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RCT_EXPORT_METHOD(multiMerge:(NSArray *)kvPairs
|
||||||
|
callback:(RCTResponseSenderBlock)callback)
|
||||||
|
{
|
||||||
|
id errorOut = [self _ensureSetup];
|
||||||
|
if (errorOut) {
|
||||||
|
callback(@[@[errorOut]]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
NSMutableArray *errors;
|
||||||
|
for (__strong NSArray *entry in kvPairs) {
|
||||||
|
id keyError;
|
||||||
|
NSString *value = [self _getValueForKey:entry[0] errorOut:&keyError];
|
||||||
|
if (keyError) {
|
||||||
|
RCTAppendError(keyError, &errors);
|
||||||
|
} else {
|
||||||
|
if (value) {
|
||||||
|
NSMutableDictionary *mergedVal = [RCTJSONParseMutable(value, &keyError) mutableCopy];
|
||||||
|
RCTMergeRecursive(mergedVal, RCTJSONParse(entry[1], &keyError));
|
||||||
|
entry = @[entry[0], RCTJSONStringify(mergedVal, &keyError)];
|
||||||
|
}
|
||||||
|
if (!keyError) {
|
||||||
|
keyError = [self _writeEntry:entry];
|
||||||
|
}
|
||||||
|
RCTAppendError(keyError, &errors);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[self _writeManifest:&errors];
|
||||||
|
if (callback) {
|
||||||
|
callback(@[errors ?: [NSNull null]]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
RCT_EXPORT_METHOD(multiRemove:(NSArray *)keys
|
RCT_EXPORT_METHOD(multiRemove:(NSArray *)keys
|
||||||
callback:(RCTResponseSenderBlock)callback)
|
callback:(RCTResponseSenderBlock)callback)
|
||||||
{
|
{
|
||||||
|
@ -10,6 +10,14 @@
|
|||||||
#import <UIKit/UIKit.h>
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
#import "RCTBridgeModule.h"
|
#import "RCTBridgeModule.h"
|
||||||
|
#import "RCTConvert.h"
|
||||||
|
|
||||||
|
@interface RCTConvert (UIStatusBar)
|
||||||
|
|
||||||
|
+ (UIStatusBarStyle)UIStatusBarStyle:(id)json;
|
||||||
|
+ (UIStatusBarAnimation)UIStatusBarAnimation:(id)json;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
@interface RCTStatusBarManager : NSObject <RCTBridgeModule>
|
@interface RCTStatusBarManager : NSObject <RCTBridgeModule>
|
||||||
|
|
||||||
|
@ -11,6 +11,21 @@
|
|||||||
|
|
||||||
#import "RCTLog.h"
|
#import "RCTLog.h"
|
||||||
|
|
||||||
|
@implementation RCTConvert (UIStatusBar)
|
||||||
|
|
||||||
|
RCT_ENUM_CONVERTER(UIStatusBarStyle, (@{
|
||||||
|
@"default": @(UIStatusBarStyleDefault),
|
||||||
|
@"light-content": @(UIStatusBarStyleLightContent),
|
||||||
|
}), UIStatusBarStyleDefault, integerValue);
|
||||||
|
|
||||||
|
RCT_ENUM_CONVERTER(UIStatusBarAnimation, (@{
|
||||||
|
@"none": @(UIStatusBarAnimationNone),
|
||||||
|
@"fade": @(UIStatusBarAnimationFade),
|
||||||
|
@"slide": @(UIStatusBarAnimationSlide),
|
||||||
|
}), UIStatusBarAnimationNone, integerValue);
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
@implementation RCTStatusBarManager
|
@implementation RCTStatusBarManager
|
||||||
|
|
||||||
static BOOL RCTViewControllerBasedStatusBarAppearance()
|
static BOOL RCTViewControllerBasedStatusBarAppearance()
|
||||||
@ -18,7 +33,8 @@ static BOOL RCTViewControllerBasedStatusBarAppearance()
|
|||||||
static BOOL value;
|
static BOOL value;
|
||||||
static dispatch_once_t onceToken;
|
static dispatch_once_t onceToken;
|
||||||
dispatch_once(&onceToken, ^{
|
dispatch_once(&onceToken, ^{
|
||||||
value = [[[NSBundle mainBundle] objectForInfoDictionaryKey:@"UIViewControllerBasedStatusBarAppearance"] ?: @YES boolValue];
|
value = [[[NSBundle mainBundle] objectForInfoDictionaryKey:
|
||||||
|
@"UIViewControllerBasedStatusBarAppearance"] ?: @YES boolValue];
|
||||||
});
|
});
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
@ -55,19 +71,4 @@ RCT_EXPORT_METHOD(setHidden:(BOOL)hidden
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSDictionary *)constantsToExport
|
|
||||||
{
|
|
||||||
return @{
|
|
||||||
@"Style": @{
|
|
||||||
@"default": @(UIStatusBarStyleDefault),
|
|
||||||
@"lightContent": @(UIStatusBarStyleLightContent),
|
|
||||||
},
|
|
||||||
@"Animation": @{
|
|
||||||
@"none": @(UIStatusBarAnimationNone),
|
|
||||||
@"fade": @(UIStatusBarAnimationFade),
|
|
||||||
@"slide": @(UIStatusBarAnimationSlide),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
@ -1397,11 +1397,6 @@ RCT_EXPORT_METHOD(clearJSResponder)
|
|||||||
NSMutableDictionary *allJSConstants = [@{
|
NSMutableDictionary *allJSConstants = [@{
|
||||||
@"customBubblingEventTypes": [self customBubblingEventTypes],
|
@"customBubblingEventTypes": [self customBubblingEventTypes],
|
||||||
@"customDirectEventTypes": [self customDirectEventTypes],
|
@"customDirectEventTypes": [self customDirectEventTypes],
|
||||||
@"NSTextAlignment": @{
|
|
||||||
@"Left": @(NSTextAlignmentLeft),
|
|
||||||
@"Center": @(NSTextAlignmentCenter),
|
|
||||||
@"Right": @(NSTextAlignmentRight),
|
|
||||||
},
|
|
||||||
@"Dimensions": @{
|
@"Dimensions": @{
|
||||||
@"window": @{
|
@"window": @{
|
||||||
@"width": @(RCTScreenSize().width),
|
@"width": @(RCTScreenSize().width),
|
||||||
@ -1413,73 +1408,6 @@ RCT_EXPORT_METHOD(clearJSResponder)
|
|||||||
@"height": @(RCTScreenSize().height),
|
@"height": @(RCTScreenSize().height),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@"StyleConstants": @{
|
|
||||||
@"PointerEventsValues": @{
|
|
||||||
@"none": @(RCTPointerEventsNone),
|
|
||||||
@"box-none": @(RCTPointerEventsBoxNone),
|
|
||||||
@"box-only": @(RCTPointerEventsBoxOnly),
|
|
||||||
@"auto": @(RCTPointerEventsUnspecified),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
@"UIText": @{
|
|
||||||
@"AutocapitalizationType": @{
|
|
||||||
@"characters": @(UITextAutocapitalizationTypeAllCharacters),
|
|
||||||
@"sentences": @(UITextAutocapitalizationTypeSentences),
|
|
||||||
@"words": @(UITextAutocapitalizationTypeWords),
|
|
||||||
@"none": @(UITextAutocapitalizationTypeNone),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
@"UITextField": @{
|
|
||||||
@"clearButtonMode": @{
|
|
||||||
@"never": @(UITextFieldViewModeNever),
|
|
||||||
@"while-editing": @(UITextFieldViewModeWhileEditing),
|
|
||||||
@"unless-editing": @(UITextFieldViewModeUnlessEditing),
|
|
||||||
@"always": @(UITextFieldViewModeAlways),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
@"UIKeyboardType": @{
|
|
||||||
@"default": @(UIKeyboardTypeDefault),
|
|
||||||
@"ascii-capable": @(UIKeyboardTypeASCIICapable),
|
|
||||||
@"numbers-and-punctuation": @(UIKeyboardTypeNumbersAndPunctuation),
|
|
||||||
@"url": @(UIKeyboardTypeURL),
|
|
||||||
@"number-pad": @(UIKeyboardTypeNumberPad),
|
|
||||||
@"phone-pad": @(UIKeyboardTypePhonePad),
|
|
||||||
@"name-phone-pad": @(UIKeyboardTypeNamePhonePad),
|
|
||||||
@"decimal-pad": @(UIKeyboardTypeDecimalPad),
|
|
||||||
@"email-address": @(UIKeyboardTypeEmailAddress),
|
|
||||||
@"twitter": @(UIKeyboardTypeTwitter),
|
|
||||||
@"web-search": @(UIKeyboardTypeWebSearch),
|
|
||||||
},
|
|
||||||
@"UIReturnKeyType": @{
|
|
||||||
@"default": @(UIReturnKeyDefault),
|
|
||||||
@"go": @(UIReturnKeyGo),
|
|
||||||
@"google": @(UIReturnKeyGoogle),
|
|
||||||
@"join": @(UIReturnKeyJoin),
|
|
||||||
@"next": @(UIReturnKeyNext),
|
|
||||||
@"route": @(UIReturnKeyRoute),
|
|
||||||
@"search": @(UIReturnKeySearch),
|
|
||||||
@"send": @(UIReturnKeySend),
|
|
||||||
@"yahoo": @(UIReturnKeyYahoo),
|
|
||||||
@"done": @(UIReturnKeyDone),
|
|
||||||
@"emergency-call": @(UIReturnKeyEmergencyCall),
|
|
||||||
},
|
|
||||||
@"UIView": @{
|
|
||||||
@"ContentMode": @{
|
|
||||||
@"ScaleToFill": @(UIViewContentModeScaleToFill),
|
|
||||||
@"ScaleAspectFit": @(UIViewContentModeScaleAspectFit),
|
|
||||||
@"ScaleAspectFill": @(UIViewContentModeScaleAspectFill),
|
|
||||||
@"Redraw": @(UIViewContentModeRedraw),
|
|
||||||
@"Center": @(UIViewContentModeCenter),
|
|
||||||
@"Top": @(UIViewContentModeTop),
|
|
||||||
@"Bottom": @(UIViewContentModeBottom),
|
|
||||||
@"Left": @(UIViewContentModeLeft),
|
|
||||||
@"Right": @(UIViewContentModeRight),
|
|
||||||
@"TopLeft": @(UIViewContentModeTopLeft),
|
|
||||||
@"TopRight": @(UIViewContentModeTopRight),
|
|
||||||
@"BottomLeft": @(UIViewContentModeBottomLeft),
|
|
||||||
@"BottomRight": @(UIViewContentModeBottomRight),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} mutableCopy];
|
} mutableCopy];
|
||||||
|
|
||||||
[_viewManagers enumerateKeysAndObjectsUsingBlock:^(NSString *name, RCTViewManager *manager, BOOL *stop) {
|
[_viewManagers enumerateKeysAndObjectsUsingBlock:^(NSString *name, RCTViewManager *manager, BOOL *stop) {
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
134FCB361A6D42D900051CC8 /* RCTSparseArray.m in Sources */ = {isa = PBXBuildFile; fileRef = 83BEE46D1A6D19BC00B5863B /* RCTSparseArray.m */; };
|
134FCB361A6D42D900051CC8 /* RCTSparseArray.m in Sources */ = {isa = PBXBuildFile; fileRef = 83BEE46D1A6D19BC00B5863B /* RCTSparseArray.m */; };
|
||||||
134FCB3D1A6E7F0800051CC8 /* RCTContextExecutor.m in Sources */ = {isa = PBXBuildFile; fileRef = 134FCB3A1A6E7F0800051CC8 /* RCTContextExecutor.m */; };
|
134FCB3D1A6E7F0800051CC8 /* RCTContextExecutor.m in Sources */ = {isa = PBXBuildFile; fileRef = 134FCB3A1A6E7F0800051CC8 /* RCTContextExecutor.m */; };
|
||||||
134FCB3E1A6E7F0800051CC8 /* RCTWebViewExecutor.m in Sources */ = {isa = PBXBuildFile; fileRef = 134FCB3C1A6E7F0800051CC8 /* RCTWebViewExecutor.m */; };
|
134FCB3E1A6E7F0800051CC8 /* RCTWebViewExecutor.m in Sources */ = {isa = PBXBuildFile; fileRef = 134FCB3C1A6E7F0800051CC8 /* RCTWebViewExecutor.m */; };
|
||||||
|
13513F3C1B1F43F400FCE529 /* RCTProgressViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 13513F3B1B1F43F400FCE529 /* RCTProgressViewManager.m */; };
|
||||||
13723B501A82FD3C00F88898 /* RCTStatusBarManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 13723B4F1A82FD3C00F88898 /* RCTStatusBarManager.m */; };
|
13723B501A82FD3C00F88898 /* RCTStatusBarManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 13723B4F1A82FD3C00F88898 /* RCTStatusBarManager.m */; };
|
||||||
1372B70A1AB030C200659ED6 /* RCTAppState.m in Sources */ = {isa = PBXBuildFile; fileRef = 1372B7091AB030C200659ED6 /* RCTAppState.m */; };
|
1372B70A1AB030C200659ED6 /* RCTAppState.m in Sources */ = {isa = PBXBuildFile; fileRef = 1372B7091AB030C200659ED6 /* RCTAppState.m */; };
|
||||||
137327E71AA5CF210034F82E /* RCTTabBar.m in Sources */ = {isa = PBXBuildFile; fileRef = 137327E01AA5CF210034F82E /* RCTTabBar.m */; };
|
137327E71AA5CF210034F82E /* RCTTabBar.m in Sources */ = {isa = PBXBuildFile; fileRef = 137327E01AA5CF210034F82E /* RCTTabBar.m */; };
|
||||||
@ -104,6 +105,8 @@
|
|||||||
134FCB3A1A6E7F0800051CC8 /* RCTContextExecutor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTContextExecutor.m; sourceTree = "<group>"; };
|
134FCB3A1A6E7F0800051CC8 /* RCTContextExecutor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTContextExecutor.m; sourceTree = "<group>"; };
|
||||||
134FCB3B1A6E7F0800051CC8 /* RCTWebViewExecutor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTWebViewExecutor.h; sourceTree = "<group>"; };
|
134FCB3B1A6E7F0800051CC8 /* RCTWebViewExecutor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTWebViewExecutor.h; sourceTree = "<group>"; };
|
||||||
134FCB3C1A6E7F0800051CC8 /* RCTWebViewExecutor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTWebViewExecutor.m; sourceTree = "<group>"; };
|
134FCB3C1A6E7F0800051CC8 /* RCTWebViewExecutor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTWebViewExecutor.m; sourceTree = "<group>"; };
|
||||||
|
13513F3A1B1F43F400FCE529 /* RCTProgressViewManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTProgressViewManager.h; sourceTree = "<group>"; };
|
||||||
|
13513F3B1B1F43F400FCE529 /* RCTProgressViewManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTProgressViewManager.m; sourceTree = "<group>"; };
|
||||||
13723B4E1A82FD3C00F88898 /* RCTStatusBarManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTStatusBarManager.h; sourceTree = "<group>"; };
|
13723B4E1A82FD3C00F88898 /* RCTStatusBarManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTStatusBarManager.h; sourceTree = "<group>"; };
|
||||||
13723B4F1A82FD3C00F88898 /* RCTStatusBarManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTStatusBarManager.m; sourceTree = "<group>"; };
|
13723B4F1A82FD3C00F88898 /* RCTStatusBarManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTStatusBarManager.m; sourceTree = "<group>"; };
|
||||||
1372B7081AB030C200659ED6 /* RCTAppState.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTAppState.h; sourceTree = "<group>"; };
|
1372B7081AB030C200659ED6 /* RCTAppState.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTAppState.h; sourceTree = "<group>"; };
|
||||||
@ -307,6 +310,8 @@
|
|||||||
58114A141AAE854800E7D092 /* RCTPickerManager.h */,
|
58114A141AAE854800E7D092 /* RCTPickerManager.h */,
|
||||||
58114A151AAE854800E7D092 /* RCTPickerManager.m */,
|
58114A151AAE854800E7D092 /* RCTPickerManager.m */,
|
||||||
13442BF31AA90E0B0037E5B0 /* RCTPointerEvents.h */,
|
13442BF31AA90E0B0037E5B0 /* RCTPointerEvents.h */,
|
||||||
|
13513F3A1B1F43F400FCE529 /* RCTProgressViewManager.h */,
|
||||||
|
13513F3B1B1F43F400FCE529 /* RCTProgressViewManager.m */,
|
||||||
131B6AF01AF1093D00FFC3E0 /* RCTSegmentedControl.h */,
|
131B6AF01AF1093D00FFC3E0 /* RCTSegmentedControl.h */,
|
||||||
131B6AF11AF1093D00FFC3E0 /* RCTSegmentedControl.m */,
|
131B6AF11AF1093D00FFC3E0 /* RCTSegmentedControl.m */,
|
||||||
131B6AF21AF1093D00FFC3E0 /* RCTSegmentedControlManager.h */,
|
131B6AF21AF1093D00FFC3E0 /* RCTSegmentedControlManager.h */,
|
||||||
@ -524,6 +529,7 @@
|
|||||||
58114A501AAE93D500E7D092 /* RCTAsyncLocalStorage.m in Sources */,
|
58114A501AAE93D500E7D092 /* RCTAsyncLocalStorage.m in Sources */,
|
||||||
832348161A77A5AA00B55238 /* Layout.c in Sources */,
|
832348161A77A5AA00B55238 /* Layout.c in Sources */,
|
||||||
14F4D38B1AE1B7E40049C042 /* RCTProfile.m in Sources */,
|
14F4D38B1AE1B7E40049C042 /* RCTProfile.m in Sources */,
|
||||||
|
13513F3C1B1F43F400FCE529 /* RCTProgressViewManager.m in Sources */,
|
||||||
14F3620D1AABD06A001CE568 /* RCTSwitch.m in Sources */,
|
14F3620D1AABD06A001CE568 /* RCTSwitch.m in Sources */,
|
||||||
14F3620E1AABD06A001CE568 /* RCTSwitchManager.m in Sources */,
|
14F3620E1AABD06A001CE568 /* RCTSwitchManager.m in Sources */,
|
||||||
13B080201A69489C00A75B9A /* RCTActivityIndicatorViewManager.m in Sources */,
|
13B080201A69489C00A75B9A /* RCTActivityIndicatorViewManager.m in Sources */,
|
||||||
|
@ -8,6 +8,13 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#import "RCTViewManager.h"
|
#import "RCTViewManager.h"
|
||||||
|
#import "RCTConvert.h"
|
||||||
|
|
||||||
|
@interface RCTConvert(UIDatePicker)
|
||||||
|
|
||||||
|
+ (UIDatePickerMode)UIDatePickerMode:(id)json;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
@interface RCTDatePickerManager : RCTViewManager
|
@interface RCTDatePickerManager : RCTViewManager
|
||||||
|
|
||||||
|
@ -10,7 +10,6 @@
|
|||||||
#import "RCTDatePickerManager.h"
|
#import "RCTDatePickerManager.h"
|
||||||
|
|
||||||
#import "RCTBridge.h"
|
#import "RCTBridge.h"
|
||||||
#import "RCTConvert.h"
|
|
||||||
#import "RCTEventDispatcher.h"
|
#import "RCTEventDispatcher.h"
|
||||||
#import "UIView+React.h"
|
#import "UIView+React.h"
|
||||||
|
|
||||||
@ -20,7 +19,7 @@ RCT_ENUM_CONVERTER(UIDatePickerMode, (@{
|
|||||||
@"time": @(UIDatePickerModeTime),
|
@"time": @(UIDatePickerModeTime),
|
||||||
@"date": @(UIDatePickerModeDate),
|
@"date": @(UIDatePickerModeDate),
|
||||||
@"datetime": @(UIDatePickerModeDateAndTime),
|
@"datetime": @(UIDatePickerModeDateAndTime),
|
||||||
//@"countdown": @(UIDatePickerModeCountDownTimer) // not supported yet
|
@"countdown": @(UIDatePickerModeCountDownTimer), // not supported yet
|
||||||
}), UIDatePickerModeTime, integerValue)
|
}), UIDatePickerModeTime, integerValue)
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@ -31,9 +30,12 @@ RCT_EXPORT_MODULE()
|
|||||||
|
|
||||||
- (UIView *)view
|
- (UIView *)view
|
||||||
{
|
{
|
||||||
|
// TODO: we crash here if the RCTDatePickerManager is released
|
||||||
|
// while the UIDatePicker is still sending onChange events. To
|
||||||
|
// fix this we should maybe subclass UIDatePicker and make it
|
||||||
|
// be its own event target.
|
||||||
UIDatePicker *picker = [[UIDatePicker alloc] init];
|
UIDatePicker *picker = [[UIDatePicker alloc] init];
|
||||||
[picker addTarget:self
|
[picker addTarget:self action:@selector(onChange:)
|
||||||
action:@selector(onChange:)
|
|
||||||
forControlEvents:UIControlEventValueChanged];
|
forControlEvents:UIControlEventValueChanged];
|
||||||
return picker;
|
return picker;
|
||||||
}
|
}
|
||||||
@ -56,17 +58,10 @@ RCT_REMAP_VIEW_PROPERTY(timeZoneOffsetInMinutes, timeZone, NSTimeZone)
|
|||||||
|
|
||||||
- (NSDictionary *)constantsToExport
|
- (NSDictionary *)constantsToExport
|
||||||
{
|
{
|
||||||
UIDatePicker *dp = [[UIDatePicker alloc] init];
|
UIDatePicker *view = [[UIDatePicker alloc] init];
|
||||||
[dp layoutIfNeeded];
|
|
||||||
|
|
||||||
return @{
|
return @{
|
||||||
@"ComponentHeight": @(CGRectGetHeight(dp.frame)),
|
@"ComponentHeight": @(view.intrinsicContentSize.height),
|
||||||
@"ComponentWidth": @(CGRectGetWidth(dp.frame)),
|
@"ComponentWidth": @(view.intrinsicContentSize.width),
|
||||||
@"DatePickerModes": @{
|
|
||||||
@"time": @(UIDatePickerModeTime),
|
|
||||||
@"date": @(UIDatePickerModeDate),
|
|
||||||
@"datetime": @(UIDatePickerModeDateAndTime),
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,10 +27,10 @@ RCT_EXPORT_VIEW_PROPERTY(selectedIndex, NSInteger)
|
|||||||
|
|
||||||
- (NSDictionary *)constantsToExport
|
- (NSDictionary *)constantsToExport
|
||||||
{
|
{
|
||||||
RCTPicker *pv = [[RCTPicker alloc] init];
|
RCTPicker *view = [[RCTPicker alloc] init];
|
||||||
return @{
|
return @{
|
||||||
@"ComponentHeight": @(CGRectGetHeight(pv.frame)),
|
@"ComponentHeight": @(view.intrinsicContentSize.height),
|
||||||
@"ComponentWidth": @(CGRectGetWidth(pv.frame))
|
@"ComponentWidth": @(view.intrinsicContentSize.width)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
14
React/Views/RCTProgressViewManager.h
Normal file
14
React/Views/RCTProgressViewManager.h
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import "RCTViewManager.h"
|
||||||
|
|
||||||
|
@interface RCTProgressViewManager : RCTViewManager
|
||||||
|
|
||||||
|
@end
|
47
React/Views/RCTProgressViewManager.m
Normal file
47
React/Views/RCTProgressViewManager.m
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import "RCTProgressViewManager.h"
|
||||||
|
|
||||||
|
#import "RCTConvert.h"
|
||||||
|
|
||||||
|
@implementation RCTConvert (RCTProgressViewManager)
|
||||||
|
|
||||||
|
RCT_ENUM_CONVERTER(UIProgressViewStyle, (@{
|
||||||
|
@"default": @(UIProgressViewStyleDefault),
|
||||||
|
@"bar": @(UIProgressViewStyleBar),
|
||||||
|
}), UIProgressViewStyleDefault, integerValue)
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation RCTProgressViewManager
|
||||||
|
|
||||||
|
RCT_EXPORT_MODULE()
|
||||||
|
|
||||||
|
- (UIView *)view
|
||||||
|
{
|
||||||
|
return [[UIProgressView alloc] init];
|
||||||
|
}
|
||||||
|
|
||||||
|
RCT_EXPORT_VIEW_PROPERTY(progressViewStyle, UIProgressViewStyle)
|
||||||
|
RCT_EXPORT_VIEW_PROPERTY(progress, float)
|
||||||
|
RCT_EXPORT_VIEW_PROPERTY(progressTintColor, UIColor)
|
||||||
|
RCT_EXPORT_VIEW_PROPERTY(trackTintColor, UIColor)
|
||||||
|
RCT_EXPORT_VIEW_PROPERTY(progressImage, UIImage)
|
||||||
|
RCT_EXPORT_VIEW_PROPERTY(trackImage, UIImage)
|
||||||
|
|
||||||
|
- (NSDictionary *)constantsToExport
|
||||||
|
{
|
||||||
|
UIProgressView *view = [[UIProgressView alloc] init];
|
||||||
|
return @{
|
||||||
|
@"ComponentHeight": @(view.intrinsicContentSize.height),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
@ -8,6 +8,13 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#import "RCTViewManager.h"
|
#import "RCTViewManager.h"
|
||||||
|
#import "RCTConvert.h"
|
||||||
|
|
||||||
|
@interface RCTConvert (UIScrollView)
|
||||||
|
|
||||||
|
+ (UIScrollViewKeyboardDismissMode)UIScrollViewKeyboardDismissMode:(id)json;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
@interface RCTScrollViewManager : RCTViewManager
|
@interface RCTScrollViewManager : RCTViewManager
|
||||||
|
|
||||||
|
@ -10,11 +10,22 @@
|
|||||||
#import "RCTScrollViewManager.h"
|
#import "RCTScrollViewManager.h"
|
||||||
|
|
||||||
#import "RCTBridge.h"
|
#import "RCTBridge.h"
|
||||||
#import "RCTConvert.h"
|
|
||||||
#import "RCTScrollView.h"
|
#import "RCTScrollView.h"
|
||||||
#import "RCTSparseArray.h"
|
#import "RCTSparseArray.h"
|
||||||
#import "RCTUIManager.h"
|
#import "RCTUIManager.h"
|
||||||
|
|
||||||
|
@implementation RCTConvert (UIScrollView)
|
||||||
|
|
||||||
|
RCT_ENUM_CONVERTER(UIScrollViewKeyboardDismissMode, (@{
|
||||||
|
@"none": @(UIScrollViewKeyboardDismissModeNone),
|
||||||
|
@"on-drag": @(UIScrollViewKeyboardDismissModeOnDrag),
|
||||||
|
@"interactive": @(UIScrollViewKeyboardDismissModeInteractive),
|
||||||
|
// Backwards compatibility
|
||||||
|
@"onDrag": @(UIScrollViewKeyboardDismissModeOnDrag),
|
||||||
|
}), UIScrollViewKeyboardDismissModeNone, integerValue)
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
@implementation RCTScrollViewManager
|
@implementation RCTScrollViewManager
|
||||||
|
|
||||||
RCT_EXPORT_MODULE()
|
RCT_EXPORT_MODULE()
|
||||||
@ -53,14 +64,10 @@ RCT_DEPRECATED_VIEW_PROPERTY(throttleScrollCallbackMS, scrollEventThrottle)
|
|||||||
- (NSDictionary *)constantsToExport
|
- (NSDictionary *)constantsToExport
|
||||||
{
|
{
|
||||||
return @{
|
return @{
|
||||||
|
// TODO: unused - remove these?
|
||||||
@"DecelerationRate": @{
|
@"DecelerationRate": @{
|
||||||
@"Normal": @(UIScrollViewDecelerationRateNormal),
|
@"normal": @(UIScrollViewDecelerationRateNormal),
|
||||||
@"Fast": @(UIScrollViewDecelerationRateFast),
|
@"fast": @(UIScrollViewDecelerationRateFast),
|
||||||
},
|
|
||||||
@"KeyboardDismissMode": @{
|
|
||||||
@"None": @(UIScrollViewKeyboardDismissModeNone),
|
|
||||||
@"Interactive": @(UIScrollViewKeyboardDismissModeInteractive),
|
|
||||||
@"OnDrag": @(UIScrollViewKeyboardDismissModeOnDrag),
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@ RCT_EXPORT_MODULE()
|
|||||||
|
|
||||||
RCT_EXPORT_VIEW_PROPERTY(caretHidden, BOOL)
|
RCT_EXPORT_VIEW_PROPERTY(caretHidden, BOOL)
|
||||||
RCT_EXPORT_VIEW_PROPERTY(autoCorrect, BOOL)
|
RCT_EXPORT_VIEW_PROPERTY(autoCorrect, BOOL)
|
||||||
RCT_EXPORT_VIEW_PROPERTY(enabled, BOOL)
|
RCT_REMAP_VIEW_PROPERTY(editable, enabled, BOOL)
|
||||||
RCT_EXPORT_VIEW_PROPERTY(placeholder, NSString)
|
RCT_EXPORT_VIEW_PROPERTY(placeholder, NSString)
|
||||||
RCT_EXPORT_VIEW_PROPERTY(placeholderTextColor, UIColor)
|
RCT_EXPORT_VIEW_PROPERTY(placeholderTextColor, UIColor)
|
||||||
RCT_EXPORT_VIEW_PROPERTY(text, NSString)
|
RCT_EXPORT_VIEW_PROPERTY(text, NSString)
|
||||||
@ -36,6 +36,7 @@ RCT_EXPORT_VIEW_PROPERTY(keyboardType, UIKeyboardType)
|
|||||||
RCT_EXPORT_VIEW_PROPERTY(returnKeyType, UIReturnKeyType)
|
RCT_EXPORT_VIEW_PROPERTY(returnKeyType, UIReturnKeyType)
|
||||||
RCT_EXPORT_VIEW_PROPERTY(enablesReturnKeyAutomatically, BOOL)
|
RCT_EXPORT_VIEW_PROPERTY(enablesReturnKeyAutomatically, BOOL)
|
||||||
RCT_EXPORT_VIEW_PROPERTY(secureTextEntry, BOOL)
|
RCT_EXPORT_VIEW_PROPERTY(secureTextEntry, BOOL)
|
||||||
|
RCT_REMAP_VIEW_PROPERTY(password, secureTextEntry, BOOL) // backwards compatibility
|
||||||
RCT_REMAP_VIEW_PROPERTY(color, textColor, UIColor)
|
RCT_REMAP_VIEW_PROPERTY(color, textColor, UIColor)
|
||||||
RCT_REMAP_VIEW_PROPERTY(autoCapitalize, autocapitalizationType, UITextAutocapitalizationType)
|
RCT_REMAP_VIEW_PROPERTY(autoCapitalize, autocapitalizationType, UITextAutocapitalizationType)
|
||||||
RCT_CUSTOM_VIEW_PROPERTY(fontSize, CGFloat, RCTTextField)
|
RCT_CUSTOM_VIEW_PROPERTY(fontSize, CGFloat, RCTTextField)
|
||||||
|
@ -62,7 +62,7 @@ if the option is boolean `1/0` or `true/false` is accepted.
|
|||||||
Here are the current options the packager accepts:
|
Here are the current options the packager accepts:
|
||||||
|
|
||||||
* `dev` boolean, defaults to true: sets a global `__DEV__` variable
|
* `dev` boolean, defaults to true: sets a global `__DEV__` variable
|
||||||
which will effect how the React Nativeg core libraries behave.
|
which will effect how the React Native core libraries behave.
|
||||||
* `minify` boolean, defaults to false: whether to minify the bundle.
|
* `minify` boolean, defaults to false: whether to minify the bundle.
|
||||||
* `runModule` boolean, defaults to true: whether to require your entry
|
* `runModule` boolean, defaults to true: whether to require your entry
|
||||||
point module. So if you requested `moduleName`, this option will add
|
point module. So if you requested `moduleName`, this option will add
|
||||||
|
Loading…
x
Reference in New Issue
Block a user