Big Updates from Fri Mar 6
- [ReactNative] Oss RCTSlider | Tadeu Zagallo - [ReactNative] Oss RCTSwitch | Tadeu Zagallo - [ReactNative] Remove ImageSourcePropType | Christopher Chedeau - [ReactNative] s/Image.sourcePropType/Image.propTypes.source/ | Christopher Chedeau - [ReactNative] s/Text.stylePropType/Text.propTypes.style/ | Christopher Chedeau - [ReactNative] s/View.stylePropType/View.propTypes.style/ | Christopher Chedeau - [ReactNative] Remove nativePropTypes | Christopher Chedeau - [ReactNative] Inline ScrollViewPropTypes | Christopher Chedeau - [ReactNative] Unify ScrollView.android and ScrollView.ios | Christopher Chedeau - [ReactNative] Move around and reformat comments for the documentation | Christopher Chedeau - Improved Geolocation API | Nick Lockwood - [React Native] Move copyProperties and mergeHelpers to github dir | Ben Alpert - Fixed some misspellings that are propagating through our code | Skotch Vail - [ReactNative] OSS DatePicker | Spencer Ahrens - [React Native] Update core modules for React 0.13 | Ben Alpert - [React Native] Update React to v0.13.0-rc2 | Ben Alpert - [react-packager] onchange endpoint that informs of changes | Amjad Masad - [react-packager] dev option needs to default to true for backwards compat | Amjad Masad
This commit is contained in:
Родитель
05ec075c94
Коммит
cb9b1f7b29
|
@ -0,0 +1,157 @@
|
|||
/**
|
||||
* Copyright 2004-present Facebook. All Rights Reserved.
|
||||
*
|
||||
* @providesModule DatePickerExample
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var React = require('react-native');
|
||||
var {
|
||||
DatePickerIOS,
|
||||
StyleSheet,
|
||||
Text,
|
||||
TextInput,
|
||||
View,
|
||||
} = React;
|
||||
|
||||
var DatePickerExample = React.createClass({
|
||||
getDefaultProps: function () {
|
||||
return {
|
||||
date: new Date(),
|
||||
timeZoneOffsetInHours: (-1) * (new Date()).getTimezoneOffset() / 60,
|
||||
};
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
return {
|
||||
date: this.props.date,
|
||||
timeZoneOffsetInHours: this.props.timeZoneOffsetInHours,
|
||||
};
|
||||
},
|
||||
|
||||
onDateChange: function(date) {
|
||||
this.setState({date: date});
|
||||
},
|
||||
|
||||
onTimezoneChange: function(event) {
|
||||
var offset = parseInt(event.nativeEvent.text, 10);
|
||||
if (isNaN(offset)) {
|
||||
return;
|
||||
}
|
||||
this.setState({timeZoneOffsetInHours: offset});
|
||||
},
|
||||
|
||||
render: function() {
|
||||
// Ideally, the timezone input would be a picker rather than a
|
||||
// text input, but we don't have any pickers yet :(
|
||||
return (
|
||||
<View>
|
||||
<WithLabel label="Value:">
|
||||
<Text>{
|
||||
this.state.date.toLocaleDateString() +
|
||||
' ' +
|
||||
this.state.date.toLocaleTimeString()
|
||||
}</Text>
|
||||
</WithLabel>
|
||||
<WithLabel label="Timezone:">
|
||||
<TextInput
|
||||
onChange={this.onTimezoneChange}
|
||||
style={styles.textinput}
|
||||
value={this.state.timeZoneOffsetInHours.toString()}
|
||||
/>
|
||||
<Text> hours from UTC</Text>
|
||||
</WithLabel>
|
||||
<Heading label="Date + time picker" />
|
||||
<DatePickerIOS
|
||||
date={this.state.date}
|
||||
mode="datetime"
|
||||
timeZoneOffsetInMinutes={this.state.timeZoneOffsetInHours * 60}
|
||||
onDateChange={this.onDateChange}
|
||||
/>
|
||||
<Heading label="Date picker" />
|
||||
<DatePickerIOS
|
||||
date={this.state.date}
|
||||
mode="date"
|
||||
timeZoneOffsetInMinutes={this.state.timeZoneOffsetInHours * 60}
|
||||
onDateChange={this.onDateChange}
|
||||
/>
|
||||
<Heading label="Time picker, 10-minute interval" />
|
||||
<DatePickerIOS
|
||||
date={this.state.date}
|
||||
mode="time"
|
||||
timeZoneOffsetInMinutes={this.state.timeZoneOffsetInHours * 60}
|
||||
onDateChange={this.onDateChange}
|
||||
minuteInterval={10}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
var WithLabel = React.createClass({
|
||||
render: function() {
|
||||
return (
|
||||
<View style={styles.labelContainer}>
|
||||
<View style={styles.labelView}>
|
||||
<Text style={styles.label}>
|
||||
{this.props.label}
|
||||
</Text>
|
||||
</View>
|
||||
{this.props.children}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
var Heading = React.createClass({
|
||||
render: function() {
|
||||
return (
|
||||
<View style={styles.headingContainer}>
|
||||
<Text style={styles.heading}>
|
||||
{this.props.label}
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
exports.title = '<DatePickerIOS>';
|
||||
exports.description = 'Select dates and times using the native UIDatePicker.';
|
||||
exports.examples = [
|
||||
{
|
||||
title: '<DatePickerIOS>',
|
||||
render: function() {
|
||||
return <DatePickerExample />;
|
||||
},
|
||||
}];
|
||||
|
||||
var styles = StyleSheet.create({
|
||||
textinput: {
|
||||
height: 26,
|
||||
width: 50,
|
||||
borderWidth: 0.5,
|
||||
borderColor: '#0f0f0f',
|
||||
padding: 4,
|
||||
fontSize: 13,
|
||||
},
|
||||
labelContainer: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
marginVertical: 2,
|
||||
},
|
||||
labelView: {
|
||||
marginRight: 10,
|
||||
paddingVertical: 2,
|
||||
},
|
||||
label: {
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
headingContainer: {
|
||||
padding: 4,
|
||||
backgroundColor: '#f6f7f8',
|
||||
},
|
||||
heading: {
|
||||
fontWeight: 'bold',
|
||||
fontSize: 14,
|
||||
},
|
||||
});
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* Copyright 2004-present Facebook. All Rights Reserved.
|
||||
*
|
||||
* @providesModule GeoLocationExample
|
||||
* @providesModule GeolocationExample
|
||||
*/
|
||||
/* eslint no-console: 0 */
|
||||
'use strict';
|
||||
|
@ -15,19 +15,19 @@ var {
|
|||
} = React;
|
||||
|
||||
exports.framework = 'React';
|
||||
exports.title = 'GeoLocation';
|
||||
exports.description = 'Examples of using the GeoLocation API.';
|
||||
exports.title = 'Geolocation';
|
||||
exports.description = 'Examples of using the Geolocation API.';
|
||||
|
||||
exports.examples = [
|
||||
{
|
||||
title: 'navigator.geolocation',
|
||||
render: function() {
|
||||
return <GeoLocationExample />;
|
||||
return <GeolocationExample />;
|
||||
},
|
||||
}
|
||||
];
|
||||
|
||||
var GeoLocationExample = React.createClass({
|
||||
var GeolocationExample = React.createClass({
|
||||
getInitialState: function() {
|
||||
return {
|
||||
initialPosition: 'unknown',
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
/**
|
||||
* Copyright 2004-present Facebook. All Rights Reserved.
|
||||
*
|
||||
* @providesModule SliderExample
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var React = require('react-native');
|
||||
var {
|
||||
Slider,
|
||||
Text,
|
||||
StyleSheet,
|
||||
View,
|
||||
} = React;
|
||||
|
||||
var SliderExample = React.createClass({
|
||||
getInitialState() {
|
||||
return {
|
||||
value: 0,
|
||||
};
|
||||
},
|
||||
|
||||
render() {
|
||||
return (
|
||||
<View>
|
||||
<Text style={styles.text} >
|
||||
{this.state.value}
|
||||
</Text>
|
||||
<Slider
|
||||
style={styles.slider}
|
||||
onValueChange={(value) => this.setState({value: value})} />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
var styles = StyleSheet.create({
|
||||
slider: {
|
||||
height: 10,
|
||||
margin: 10,
|
||||
},
|
||||
text: {
|
||||
fontSize: 14,
|
||||
textAlign: 'center',
|
||||
fontWeight: 'bold',
|
||||
margin: 10,
|
||||
},
|
||||
});
|
||||
|
||||
exports.title = '<Slider>';
|
||||
exports.description = 'Slider input for numeric values';
|
||||
exports.examples = [
|
||||
{
|
||||
title: 'Slider',
|
||||
render() { return <SliderExample />; }
|
||||
}
|
||||
];
|
|
@ -0,0 +1,141 @@
|
|||
/**
|
||||
* Copyright 2004-present Facebook. All Rights Reserved.
|
||||
*
|
||||
* @providesModule SwitchExample
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var React = require('react-native');
|
||||
var {
|
||||
SwitchIOS,
|
||||
Text,
|
||||
View
|
||||
} = React;
|
||||
|
||||
var BasicSwitchExample = React.createClass({
|
||||
getInitialState() {
|
||||
return {
|
||||
trueSwitchIsOn: true,
|
||||
falseSwitchIsOn: false,
|
||||
};
|
||||
},
|
||||
render() {
|
||||
return (
|
||||
<View>
|
||||
<SwitchIOS
|
||||
onValueChange={(value) => this.setState({falseSwitchIsOn: value})}
|
||||
style={{marginBottom: 10}}
|
||||
value={this.state.falseSwitchIsOn} />
|
||||
<SwitchIOS
|
||||
onValueChange={(value) => this.setState({trueSwitchIsOn: value})}
|
||||
value={this.state.trueSwitchIsOn} />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
var DisabledSwitchExample = React.createClass({
|
||||
render() {
|
||||
return (
|
||||
<View>
|
||||
<SwitchIOS
|
||||
disabled={true}
|
||||
style={{marginBottom: 10}}
|
||||
value={true} />
|
||||
<SwitchIOS
|
||||
disabled={true}
|
||||
value={false} />
|
||||
</View>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
var ColorSwitchExample = React.createClass({
|
||||
getInitialState() {
|
||||
return {
|
||||
colorTrueSwitchIsOn: true,
|
||||
colorFalseSwitchIsOn: false,
|
||||
};
|
||||
},
|
||||
render() {
|
||||
return (
|
||||
<View>
|
||||
<SwitchIOS
|
||||
onValueChange={(value) => this.setState({colorFalseSwitchIsOn: value})}
|
||||
onTintColor="#00ff00"
|
||||
style={{marginBottom: 10}}
|
||||
thumbTintColor="#0000ff"
|
||||
tintColor="#ff0000"
|
||||
value={this.state.colorFalseSwitchIsOn} />
|
||||
<SwitchIOS
|
||||
onValueChange={(value) => this.setState({colorTrueSwitchIsOn: value})}
|
||||
onTintColor="#00ff00"
|
||||
thumbTintColor="#0000ff"
|
||||
tintColor="#ff0000"
|
||||
value={this.state.colorTrueSwitchIsOn} />
|
||||
</View>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
var EventSwitchExample = React.createClass({
|
||||
getInitialState() {
|
||||
return {
|
||||
eventSwitchIsOn: false,
|
||||
eventSwitchRegressionIsOn: true,
|
||||
};
|
||||
},
|
||||
render() {
|
||||
return (
|
||||
<View style={{ flexDirection: 'row', justifyContent: 'space-around' }}>
|
||||
<View>
|
||||
<SwitchIOS
|
||||
onValueChange={(value) => this.setState({eventSwitchIsOn: value})}
|
||||
style={{marginBottom: 10}}
|
||||
value={this.state.eventSwitchIsOn} />
|
||||
<SwitchIOS
|
||||
onValueChange={(value) => this.setState({eventSwitchIsOn: value})}
|
||||
style={{marginBottom: 10}}
|
||||
value={this.state.eventSwitchIsOn} />
|
||||
<Text>{this.state.eventSwitchIsOn ? "On" : "Off"}</Text>
|
||||
</View>
|
||||
<View>
|
||||
<SwitchIOS
|
||||
onValueChange={(value) => this.setState({eventSwitchRegressionIsOn: value})}
|
||||
style={{marginBottom: 10}}
|
||||
value={this.state.eventSwitchRegressionIsOn} />
|
||||
<SwitchIOS
|
||||
onValueChange={(value) => this.setState({eventSwitchRegressionIsOn: value})}
|
||||
style={{marginBottom: 10}}
|
||||
value={this.state.eventSwitchRegressionIsOn} />
|
||||
<Text>{this.state.eventSwitchRegressionIsOn ? "On" : "Off"}</Text>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
exports.title = '<SwitchIOS>';
|
||||
exports.description = 'Native boolean input';
|
||||
exports.examples = [
|
||||
{
|
||||
title: 'Switches can be set to true or false',
|
||||
render() { return <BasicSwitchExample />; }
|
||||
},
|
||||
{
|
||||
title: 'Switches can be disabled',
|
||||
render() { return <DisabledSwitchExample />; }
|
||||
},
|
||||
{
|
||||
title: 'Custom colors can be provided',
|
||||
render() { return <ColorSwitchExample />; }
|
||||
},
|
||||
{
|
||||
title: 'Change events can be detected',
|
||||
render() { return <EventSwitchExample />; }
|
||||
},
|
||||
{
|
||||
title: 'Switches are controlled components',
|
||||
render() { return <SwitchIOS />; }
|
||||
}
|
||||
];
|
|
@ -11,6 +11,7 @@
|
|||
134180011AA9153C003F314A /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 13417FEF1AA914B8003F314A /* libRCTText.a */; };
|
||||
134180021AA9153C003F314A /* libReactKit.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 13417FFF1AA91531003F314A /* libReactKit.a */; };
|
||||
1341802C1AA9178B003F314A /* libRCTNetwork.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1341802B1AA91779003F314A /* libRCTNetwork.a */; };
|
||||
134A8A2A1AACED7A00945AAE /* libRCTGeolocation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 134A8A251AACED6A00945AAE /* libRCTGeolocation.a */; };
|
||||
13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.m */; };
|
||||
13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB11A68108700A75B9A /* LaunchScreen.xib */; };
|
||||
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
|
||||
|
@ -46,6 +47,13 @@
|
|||
remoteGlobalIDString = 58B511DB1A9E6C8500147676;
|
||||
remoteInfo = RCTNetwork;
|
||||
};
|
||||
134A8A241AACED6A00945AAE /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 134A8A201AACED6A00945AAE /* RCTGeolocation.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 134814201AA4EA6300B7C361;
|
||||
remoteInfo = RCTGeolocation;
|
||||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
|
@ -53,6 +61,7 @@
|
|||
13417FEA1AA914B8003F314A /* RCTText.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTText.xcodeproj; path = ../../Libraries/Text/RCTText.xcodeproj; sourceTree = "<group>"; };
|
||||
13417FFA1AA91531003F314A /* ReactKit.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = ReactKit.xcodeproj; path = ../../ReactKit/ReactKit.xcodeproj; sourceTree = "<group>"; };
|
||||
134180261AA91779003F314A /* RCTNetwork.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTNetwork.xcodeproj; path = ../../Libraries/Network/RCTNetwork.xcodeproj; sourceTree = "<group>"; };
|
||||
134A8A201AACED6A00945AAE /* RCTGeolocation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTGeolocation.xcodeproj; path = ../../Libraries/Geolocation/RCTGeolocation.xcodeproj; sourceTree = "<group>"; };
|
||||
13B07F961A680F5B00A75B9A /* UIExplorer.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = UIExplorer.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
|
||||
13B07FB01A68108700A75B9A /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
|
||||
|
@ -67,6 +76,7 @@
|
|||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
134A8A2A1AACED7A00945AAE /* libRCTGeolocation.a in Frameworks */,
|
||||
1341802C1AA9178B003F314A /* libRCTNetwork.a in Frameworks */,
|
||||
134180011AA9153C003F314A /* libRCTText.a in Frameworks */,
|
||||
134180021AA9153C003F314A /* libReactKit.a in Frameworks */,
|
||||
|
@ -80,6 +90,7 @@
|
|||
1316A21D1AA397F400C0188E /* Libraries */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
134A8A201AACED6A00945AAE /* RCTGeolocation.xcodeproj */,
|
||||
13417FFA1AA91531003F314A /* ReactKit.xcodeproj */,
|
||||
134180261AA91779003F314A /* RCTNetwork.xcodeproj */,
|
||||
13417FEA1AA914B8003F314A /* RCTText.xcodeproj */,
|
||||
|
@ -120,6 +131,14 @@
|
|||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
134A8A211AACED6A00945AAE /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
134A8A251AACED6A00945AAE /* libRCTGeolocation.a */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
13B07FAE1A68108700A75B9A /* UIExplorer */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -191,6 +210,10 @@
|
|||
productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */;
|
||||
projectDirPath = "";
|
||||
projectReferences = (
|
||||
{
|
||||
ProductGroup = 134A8A211AACED6A00945AAE /* Products */;
|
||||
ProjectRef = 134A8A201AACED6A00945AAE /* RCTGeolocation.xcodeproj */;
|
||||
},
|
||||
{
|
||||
ProductGroup = 13417FE41AA91428003F314A /* Products */;
|
||||
ProjectRef = 13417FE31AA91428003F314A /* RCTImage.xcodeproj */;
|
||||
|
@ -244,6 +267,13 @@
|
|||
remoteRef = 1341802A1AA91779003F314A /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
134A8A251AACED6A00945AAE /* libRCTGeolocation.a */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = archive.ar;
|
||||
path = libRCTGeolocation.a;
|
||||
remoteRef = 134A8A241AACED6A00945AAE /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
/* End PBXReferenceProxy section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
|
|
7
Examples/UIExplorer/UIExplorer.xcodeproj/project.xcworkspace/contents.xcworkspacedata
сгенерированный
Normal file
7
Examples/UIExplorer/UIExplorer.xcodeproj/project.xcworkspace/contents.xcworkspacedata
сгенерированный
Normal file
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:UIExplorer.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
|
@ -31,8 +31,11 @@ var EXAMPLES = [
|
|||
require('./TouchableExample'),
|
||||
require('./ActivityIndicatorExample'),
|
||||
require('./ScrollViewExample'),
|
||||
require('./GeoLocationExample'),
|
||||
require('./DatePickerExample'),
|
||||
require('./GeolocationExample'),
|
||||
require('./TabBarExample'),
|
||||
require('./SwitchExample'),
|
||||
require('./SliderExample'),
|
||||
];
|
||||
|
||||
var UIExplorerList = React.createClass({
|
||||
|
|
|
@ -15,7 +15,6 @@ var View = require('View');
|
|||
|
||||
var createReactIOSNativeComponentClass = require('createReactIOSNativeComponentClass');
|
||||
var keyMirror = require('keyMirror');
|
||||
var keyOf = require('keyOf');
|
||||
var merge = require('merge');
|
||||
|
||||
var SpinnerSize = keyMirror({
|
||||
|
|
|
@ -0,0 +1,155 @@
|
|||
/**
|
||||
* Copyright 2004-present Facebook. All Rights Reserved.
|
||||
*
|
||||
* @providesModule DatePickerIOS
|
||||
*
|
||||
* This is a controlled component version of RKDatePickerIOS
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var NativeMethodsMixin = require('NativeMethodsMixin');
|
||||
var PropTypes = require('ReactPropTypes');
|
||||
var React = require('React');
|
||||
var ReactIOSViewAttributes = require('ReactIOSViewAttributes');
|
||||
var RKDatePickerIOSConsts = require('NativeModules').RKUIManager.RCTDatePicker.Constants;
|
||||
var StyleSheet = require('StyleSheet');
|
||||
var View = require('View');
|
||||
|
||||
var createReactIOSNativeComponentClass =
|
||||
require('createReactIOSNativeComponentClass');
|
||||
var merge = require('merge');
|
||||
|
||||
var DATEPICKER = 'datepicker';
|
||||
|
||||
/**
|
||||
* Use `DatePickerIOS` to render a date/time picker (selector) on iOS. This is
|
||||
* a controlled component, so you must hook in to the `onDateChange` callback
|
||||
* and update the `date` prop in order for the component to update, otherwise
|
||||
* the user's change will be reverted immediately to reflect `props.date` as the
|
||||
* source of truth.
|
||||
*/
|
||||
var DatePickerIOS = React.createClass({
|
||||
mixins: [NativeMethodsMixin],
|
||||
|
||||
propTypes: {
|
||||
/**
|
||||
* The currently selected date.
|
||||
*/
|
||||
date: PropTypes.instanceOf(Date).isRequired,
|
||||
|
||||
/**
|
||||
* Date change handler.
|
||||
*
|
||||
* This is called when the user changes the date or time in the UI.
|
||||
* The first and only argument is a Date object representing the new
|
||||
* date and time.
|
||||
*/
|
||||
onDateChange: PropTypes.func.isRequired,
|
||||
|
||||
/**
|
||||
* Maximum date.
|
||||
*
|
||||
* Restricts the range of possible date/time values.
|
||||
*/
|
||||
maximumDate: PropTypes.instanceOf(Date),
|
||||
|
||||
/**
|
||||
* Minimum date.
|
||||
*
|
||||
* Restricts the range of possible date/time values.
|
||||
*/
|
||||
minimumDate: PropTypes.instanceOf(Date),
|
||||
|
||||
/**
|
||||
* The date picker mode.
|
||||
*
|
||||
* Valid modes on iOS are: 'date', 'time', 'datetime'.
|
||||
*/
|
||||
mode: PropTypes.oneOf(Object.keys(RKDatePickerIOSConsts.DatePickerModes)),
|
||||
|
||||
/**
|
||||
* The interval at which minutes can be selected.
|
||||
*/
|
||||
minuteInterval: PropTypes.oneOf([1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30]),
|
||||
|
||||
/**
|
||||
* Timezone offset in seconds.
|
||||
*
|
||||
* By default, the date picker will use the device's timezone. With this
|
||||
* parameter, it is possible to force a certain timezone offset. For
|
||||
* instance, to show times in Pacific Standard Time, pass -7 * 60.
|
||||
*/
|
||||
timeZoneOffsetInMinutes: PropTypes.number,
|
||||
},
|
||||
|
||||
getDefaultProps: function() {
|
||||
return {
|
||||
mode: 'datetime',
|
||||
};
|
||||
},
|
||||
|
||||
_onChange: function(event) {
|
||||
var nativeTimeStamp = event.nativeEvent.timestamp;
|
||||
this.props.onDateChange && this.props.onDateChange(
|
||||
new Date(nativeTimeStamp)
|
||||
);
|
||||
this.props.onChange && this.props.onChange(event);
|
||||
|
||||
// We expect the onChange* handlers to be in charge of updating our `date`
|
||||
// prop. That way they can also disallow/undo/mutate the selection of
|
||||
// certain values. In other words, the embedder of this component should
|
||||
// be the source of truth, not the native component.
|
||||
var propsTimeStamp = this.props.date.getTime();
|
||||
if (nativeTimeStamp !== propsTimeStamp) {
|
||||
this.refs[DATEPICKER].setNativeProps({
|
||||
date: propsTimeStamp,
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var props = this.props;
|
||||
return (
|
||||
<View style={props.style}>
|
||||
<RKDatePickerIOS
|
||||
ref={DATEPICKER}
|
||||
style={styles.rkDatePickerIOS}
|
||||
date={props.date.getTime()}
|
||||
maximumDate={
|
||||
props.maximumDate ? props.maximumDate.getTime() : undefined
|
||||
}
|
||||
minimumDate={
|
||||
props.minimumDate ? props.minimumDate.getTime() : undefined
|
||||
}
|
||||
mode={RKDatePickerIOSConsts.DatePickerModes[props.mode]}
|
||||
minuteInterval={props.minuteInterval}
|
||||
timeZoneOffsetInMinutes={props.timeZoneOffsetInMinutes}
|
||||
onChange={this._onChange}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
var styles = StyleSheet.create({
|
||||
rkDatePickerIOS: {
|
||||
height: RKDatePickerIOSConsts.ComponentHeight,
|
||||
width: RKDatePickerIOSConsts.ComponentWidth,
|
||||
},
|
||||
});
|
||||
|
||||
var rkDatePickerIOSAttributes = merge(ReactIOSViewAttributes.UIView, {
|
||||
date: true,
|
||||
maximumDate: true,
|
||||
minimumDate: true,
|
||||
mode: true,
|
||||
minuteInterval: true,
|
||||
timeZoneOffsetInMinutes: true,
|
||||
});
|
||||
|
||||
var RKDatePickerIOS = createReactIOSNativeComponentClass({
|
||||
validAttributes: rkDatePickerIOSAttributes,
|
||||
uiViewClassName: 'RCTDatePicker',
|
||||
});
|
||||
|
||||
module.exports = DatePickerIOS;
|
|
@ -19,29 +19,42 @@ var isEmpty = require('isEmpty');
|
|||
|
||||
var PropTypes = React.PropTypes;
|
||||
|
||||
var DEFAULT_PAGE_SIZE = 1;
|
||||
var DEFAULT_INITIAL_ROWS = 10;
|
||||
var DEFAULT_SCROLL_RENDER_AHEAD = 1000;
|
||||
var DEFAULT_END_REACHED_THRESHOLD = 1000;
|
||||
var DEFAULT_SCROLL_CALLBACK_THROTTLE = 50;
|
||||
var RENDER_INTERVAL = 20;
|
||||
var SCROLLVIEW_REF = 'listviewscroll';
|
||||
|
||||
|
||||
/**
|
||||
* ListView - A core component designed for efficient display of vertically
|
||||
* scrolling lists of changing data. The minimal API is to create a
|
||||
* `ListViewDataSource`, populate it with a simple array of data blobs, and
|
||||
* `ListView.DataSource`, populate it with a simple array of data blobs, and
|
||||
* instantiate a `ListView` component with that data source and a `renderRow`
|
||||
* callback which takes a blob from the data array and returns a renderable
|
||||
* component. Minimal example:
|
||||
* component.
|
||||
*
|
||||
* getInitialState: function() {
|
||||
* var ds = new ListViewDataSource({rowHasChanged: (r1, r2) => r1 !== r2});
|
||||
* return {
|
||||
* dataSource: ds.cloneWithRows(['row 1', 'row 2']),
|
||||
* };
|
||||
* },
|
||||
* Minimal example:
|
||||
*
|
||||
* render: function() {
|
||||
* return (
|
||||
* <ListView
|
||||
* dataSource={this.state.dataSource}
|
||||
* renderRow={(rowData) => <Text>{rowData}</Text>}
|
||||
* />
|
||||
* );
|
||||
* },
|
||||
* ```
|
||||
* getInitialState: function() {
|
||||
* var ds = new ListViewDataSource({rowHasChanged: (r1, r2) => r1 !== r2});
|
||||
* return {
|
||||
* dataSource: ds.cloneWithRows(['row 1', 'row 2']),
|
||||
* };
|
||||
* },
|
||||
*
|
||||
* render: function() {
|
||||
* return (
|
||||
* <ListView
|
||||
* dataSource={this.state.dataSource}
|
||||
* renderRow={(rowData) => <Text>{rowData}</Text>}
|
||||
* />
|
||||
* );
|
||||
* },
|
||||
* ```
|
||||
*
|
||||
* ListView also supports more advanced features, including sections with sticky
|
||||
* section headers, header and footer support, callbacks on reaching the end of
|
||||
|
@ -61,19 +74,8 @@ var PropTypes = React.PropTypes;
|
|||
* event-loop (customizable with the `pageSize` prop). This breaks up the
|
||||
* work into smaller chunks to reduce the chance of dropping frames while
|
||||
* rendering rows.
|
||||
*
|
||||
* Check out `ListViewSimpleExample.js`, `ListViewDataSource.js`, and the Movies
|
||||
* app for more info and example usage.
|
||||
*/
|
||||
|
||||
var DEFAULT_PAGE_SIZE = 1;
|
||||
var DEFAULT_INITIAL_ROWS = 10;
|
||||
var DEFAULT_SCROLL_RENDER_AHEAD = 1000;
|
||||
var DEFAULT_END_REACHED_THRESHOLD = 1000;
|
||||
var DEFAULT_SCROLL_CALLBACK_THROTTLE = 50;
|
||||
var RENDER_INTERVAL = 20;
|
||||
var SCROLLVIEW_REF = 'listviewscroll';
|
||||
|
||||
var ListView = React.createClass({
|
||||
mixins: [ScrollResponder.Mixin, TimerMixin],
|
||||
|
||||
|
|
|
@ -19,80 +19,6 @@ var invariant = require('invariant');
|
|||
var logError = require('logError');
|
||||
var merge = require('merge');
|
||||
|
||||
/**
|
||||
* NavigatorIOS wraps UIKit navigation and allows you to add back-swipe
|
||||
* functionality across your app.
|
||||
*
|
||||
* See UIExplorerApp and NavigatorIOSExample for a full example
|
||||
*
|
||||
* ======================= NavigatorIOS Routes ================================
|
||||
* A route is an object used to describe each page in the navigator. The first
|
||||
* route is provided to NavigatorIOS as `initialRoute`:
|
||||
*
|
||||
* ```
|
||||
* render: function() {
|
||||
* return (
|
||||
* <NavigatorIOS
|
||||
* initialRoute={{
|
||||
* component: MyView,
|
||||
* title: 'My View Title',
|
||||
* passProps: { myProp: 'foo' },
|
||||
* }}/>
|
||||
* );
|
||||
* },
|
||||
* ```
|
||||
*
|
||||
* Now MyView will be rendered by the navigator. It will recieve the route
|
||||
* object in the `route` prop, a navigator, and all of the props specified in
|
||||
* `passProps`.
|
||||
*
|
||||
* See the initialRoute propType for a complete definition of a route.
|
||||
*
|
||||
* ====================== NavigatorIOS Navigator ==============================
|
||||
* A `navigator` is an object of navigation functions that a view can call. It
|
||||
* is passed as a prop to any component rendered by NavigatorIOS.
|
||||
*
|
||||
* ```
|
||||
* var MyView = React.createClass({
|
||||
* _handleBackButtonPress: function() {
|
||||
* this.props.navigator.pop();
|
||||
* },
|
||||
* _handleNextButtonPress: function() {
|
||||
* this.props.navigator.push(nextRoute);
|
||||
* },
|
||||
* ...
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* A navigation object contains the following functions:
|
||||
* - `push(route)` - Navigate forward to a new route
|
||||
* - `pop()` - Go back one page
|
||||
* - `popN(n)` - Go back N pages at once. When N=1, behavior matches `pop()`
|
||||
* - `replace(route)` - Replace the route for the current page and immediately
|
||||
* load the view for the new route
|
||||
* - `replacePrevious(route)` - Replace the route/view for the previous page
|
||||
* - `replacePreviousAndPop(route)` - Replaces the previous route/view and
|
||||
* transitions back to it
|
||||
* - `resetTo(route)` - Replaces the top item and popToTop
|
||||
* - `popToRoute(route)` - Go back to the item for a particular route object
|
||||
* - `popToTop()` - Go back to the top item
|
||||
*
|
||||
* Navigator functions are also available on the NavigatorIOS component:
|
||||
*
|
||||
* ```
|
||||
* var MyView = React.createClass({
|
||||
* _handleNavigationRequest: function() {
|
||||
* this.refs.nav.push(otherRoute);
|
||||
* },
|
||||
* render: () => (
|
||||
* <NavigatorIOS
|
||||
* ref='nav',
|
||||
* initialRoute={...}/>
|
||||
* ),
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
*/
|
||||
var TRANSITIONER_REF = 'transitionerRef';
|
||||
|
||||
var PropTypes = React.PropTypes;
|
||||
|
@ -153,6 +79,83 @@ var NavigatorTransitionerIOS = React.createClass({
|
|||
* `<NavigatorIOS>` also removes children that will no longer be needed
|
||||
* (after the pop of a child has been fully completed/animated out).
|
||||
*/
|
||||
|
||||
/**
|
||||
* NavigatorIOS wraps UIKit navigation and allows you to add back-swipe
|
||||
* functionality across your app.
|
||||
*
|
||||
* #### Routes
|
||||
* A route is an object used to describe each page in the navigator. The first
|
||||
* route is provided to NavigatorIOS as `initialRoute`:
|
||||
*
|
||||
* ```
|
||||
* render: function() {
|
||||
* return (
|
||||
* <NavigatorIOS
|
||||
* initialRoute={{
|
||||
* component: MyView,
|
||||
* title: 'My View Title',
|
||||
* passProps: { myProp: 'foo' },
|
||||
* }}
|
||||
* />
|
||||
* );
|
||||
* },
|
||||
* ```
|
||||
*
|
||||
* Now MyView will be rendered by the navigator. It will recieve the route
|
||||
* object in the `route` prop, a navigator, and all of the props specified in
|
||||
* `passProps`.
|
||||
*
|
||||
* See the initialRoute propType for a complete definition of a route.
|
||||
*
|
||||
* #### Navigator
|
||||
*
|
||||
* A `navigator` is an object of navigation functions that a view can call. It
|
||||
* is passed as a prop to any component rendered by NavigatorIOS.
|
||||
*
|
||||
* ```
|
||||
* var MyView = React.createClass({
|
||||
* _handleBackButtonPress: function() {
|
||||
* this.props.navigator.pop();
|
||||
* },
|
||||
* _handleNextButtonPress: function() {
|
||||
* this.props.navigator.push(nextRoute);
|
||||
* },
|
||||
* ...
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* A navigation object contains the following functions:
|
||||
*
|
||||
* - `push(route)` - Navigate forward to a new route
|
||||
* - `pop()` - Go back one page
|
||||
* - `popN(n)` - Go back N pages at once. When N=1, behavior matches `pop()`
|
||||
* - `replace(route)` - Replace the route for the current page and immediately
|
||||
* load the view for the new route
|
||||
* - `replacePrevious(route)` - Replace the route/view for the previous page
|
||||
* - `replacePreviousAndPop(route)` - Replaces the previous route/view and
|
||||
* transitions back to it
|
||||
* - `resetTo(route)` - Replaces the top item and popToTop
|
||||
* - `popToRoute(route)` - Go back to the item for a particular route object
|
||||
* - `popToTop()` - Go back to the top item
|
||||
*
|
||||
* Navigator functions are also available on the NavigatorIOS component:
|
||||
*
|
||||
* ```
|
||||
* var MyView = React.createClass({
|
||||
* _handleNavigationRequest: function() {
|
||||
* this.refs.nav.push(otherRoute);
|
||||
* },
|
||||
* render: () => (
|
||||
* <NavigatorIOS
|
||||
* ref="nav"
|
||||
* initialRoute={...}
|
||||
* />
|
||||
* ),
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
*/
|
||||
var NavigatorIOS = React.createClass({
|
||||
|
||||
propTypes: {
|
||||
|
@ -199,7 +202,7 @@ var NavigatorIOS = React.createClass({
|
|||
/**
|
||||
* Styles for the navigation item containing the component
|
||||
*/
|
||||
wrapperStyle: View.stylePropType,
|
||||
wrapperStyle: View.propTypes.style,
|
||||
|
||||
}).isRequired,
|
||||
|
||||
|
@ -207,7 +210,7 @@ var NavigatorIOS = React.createClass({
|
|||
* The default wrapper style for components in the navigator.
|
||||
* A common use case is to set the backgroundColor for every page
|
||||
*/
|
||||
itemWrapperStyle: View.stylePropType,
|
||||
itemWrapperStyle: View.propTypes.style,
|
||||
|
||||
/**
|
||||
* The color used for buttons in the navigation bar
|
||||
|
|
|
@ -5,26 +5,27 @@
|
|||
*/
|
||||
'use strict';
|
||||
|
||||
var ArrayOfPropType = require('ArrayOfPropType');
|
||||
var EdgeInsetsPropType = require('EdgeInsetsPropType');
|
||||
var Platform = require('Platform');
|
||||
var PointPropType = require('PointPropType');
|
||||
var RCTScrollView = require('NativeModules').RKUIManager.RCTScrollView;
|
||||
var RCTScrollViewConsts = RCTScrollView.Constants;
|
||||
var React = require('React');
|
||||
var ReactIOSViewAttributes = require('ReactIOSViewAttributes');
|
||||
var ReactIOSTagHandles = require('ReactIOSTagHandles');
|
||||
var RKScrollView = require('NativeModules').RKUIManager.RCTScrollView;
|
||||
var RKScrollViewConsts = RKScrollView.Constants;
|
||||
var ReactIOSViewAttributes = require('ReactIOSViewAttributes');
|
||||
var RKUIManager = require('NativeModulesDeprecated').RKUIManager;
|
||||
var ScrollResponder = require('ScrollResponder');
|
||||
var ScrollViewPropTypes = require('ScrollViewPropTypes');
|
||||
var StyleSheetPropType = require('StyleSheetPropType');
|
||||
var StyleSheet = require('StyleSheet');
|
||||
var StyleSheetPropType = require('StyleSheetPropType');
|
||||
var View = require('View');
|
||||
var ViewStylePropTypes = require('ViewStylePropTypes');
|
||||
|
||||
var createReactIOSNativeComponentClass = require('createReactIOSNativeComponentClass');
|
||||
var deepDiffer = require('deepDiffer');
|
||||
var flattenStyle = require('flattenStyle');
|
||||
var insetsDiffer = require('insetsDiffer');
|
||||
var invariant = require('invariant');
|
||||
var merge = require('merge');
|
||||
var nativePropType = require('nativePropType');
|
||||
var validAttributesFromPropTypes = require('validAttributesFromPropTypes');
|
||||
var pointsDiffer = require('pointsDiffer');
|
||||
|
||||
var PropTypes = React.PropTypes;
|
||||
|
||||
|
@ -32,13 +33,13 @@ var SCROLLVIEW = 'ScrollView';
|
|||
var INNERVIEW = 'InnerScrollView';
|
||||
|
||||
var keyboardDismissModeConstants = {
|
||||
'none': RKScrollViewConsts.KeyboardDismissMode.None, // default
|
||||
'interactive': RKScrollViewConsts.KeyboardDismissMode.Interactive,
|
||||
'onDrag': RKScrollViewConsts.KeyboardDismissMode.OnDrag,
|
||||
'none': RCTScrollViewConsts.KeyboardDismissMode.None, // default
|
||||
'interactive': RCTScrollViewConsts.KeyboardDismissMode.Interactive,
|
||||
'onDrag': RCTScrollViewConsts.KeyboardDismissMode.OnDrag,
|
||||
};
|
||||
|
||||
/**
|
||||
* `React` component that wraps platform `RKScrollView` while providing
|
||||
* Component that wraps platform ScrollView while providing
|
||||
* integration with touch locking "responder" system.
|
||||
*
|
||||
* Doesn't yet support other contained responders from blocking this scroll
|
||||
|
@ -46,28 +47,49 @@ var keyboardDismissModeConstants = {
|
|||
*/
|
||||
|
||||
var ScrollView = React.createClass({
|
||||
|
||||
// Only for compatibility with Android which is not yet up to date,
|
||||
// DO NOT ADD NEW CALL SITES!
|
||||
statics: {
|
||||
keyboardDismissMode: {
|
||||
None: 'none',
|
||||
Interactive: 'interactive',
|
||||
OnDrag: 'onDrag',
|
||||
},
|
||||
},
|
||||
|
||||
propTypes: {
|
||||
...ScrollViewPropTypes,
|
||||
automaticallyAdjustContentInsets: PropTypes.bool, // true
|
||||
contentInset: EdgeInsetsPropType, // zeros
|
||||
contentOffset: PointPropType, // zeros
|
||||
onScroll: PropTypes.func,
|
||||
onScrollAnimationEnd: PropTypes.func,
|
||||
scrollEnabled: PropTypes.bool, // tre
|
||||
scrollIndicatorInsets: EdgeInsetsPropType, // zeros
|
||||
showsHorizontalScrollIndicator: PropTypes.bool,
|
||||
showsVerticalScrollIndicator: PropTypes.bool,
|
||||
style: StyleSheetPropType(ViewStylePropTypes),
|
||||
throttleScrollCallbackMS: PropTypes.number, // null
|
||||
|
||||
/**
|
||||
* When true, the scroll view bounces horizontally when it reaches the end
|
||||
* even if the content is smaller than the scroll view itself. The default
|
||||
* value is true when `horizontal={true}` and false otherwise.
|
||||
*/
|
||||
alwaysBounceHorizontal: nativePropType(PropTypes.bool),
|
||||
alwaysBounceHorizontal: PropTypes.bool,
|
||||
/**
|
||||
* When true, the scroll view bounces vertically when it reaches the end
|
||||
* even if the content is smaller than the scroll view itself. The default
|
||||
* value is false when `horizontal={true}` and true otherwise.
|
||||
*/
|
||||
alwaysBounceVertical: nativePropType(PropTypes.bool),
|
||||
alwaysBounceVertical: PropTypes.bool,
|
||||
/**
|
||||
* When true, the scroll view automatically centers the content when the
|
||||
* content is smaller than the scroll view bounds; when the content is
|
||||
* larger than the scroll view, this property has no effect. The default
|
||||
* value is false.
|
||||
*/
|
||||
centerContent: nativePropType(PropTypes.bool),
|
||||
centerContent: PropTypes.bool,
|
||||
/**
|
||||
* These styles will be applied to the scroll view content container which
|
||||
* wraps all of the child views. Example:
|
||||
|
@ -90,7 +112,7 @@ var ScrollView = React.createClass({
|
|||
* - Normal: 0.998 (the default)
|
||||
* - Fast: 0.9
|
||||
*/
|
||||
decelerationRate: nativePropType(PropTypes.number),
|
||||
decelerationRate: PropTypes.number,
|
||||
/**
|
||||
* When true, the scroll view's children are arranged horizontally in a row
|
||||
* instead of vertically in a column. The default value is false.
|
||||
|
@ -115,26 +137,26 @@ var ScrollView = React.createClass({
|
|||
* taps, and the keyboard will not dismiss automatically. The default value
|
||||
* is false.
|
||||
*/
|
||||
keyboardShouldPersistTaps: nativePropType(PropTypes.bool),
|
||||
keyboardShouldPersistTaps: PropTypes.bool,
|
||||
/**
|
||||
* The maximum allowed zoom scale. The default value is 1.0.
|
||||
*/
|
||||
maximumZoomScale: nativePropType(PropTypes.number),
|
||||
maximumZoomScale: PropTypes.number,
|
||||
/**
|
||||
* The minimum allowed zoom scale. The default value is 1.0.
|
||||
*/
|
||||
minimumZoomScale: nativePropType(PropTypes.number),
|
||||
minimumZoomScale: PropTypes.number,
|
||||
/**
|
||||
* When true, the scroll view stops on multiples of the scroll view's size
|
||||
* when scrolling. This can be used for horizontal pagination. The default
|
||||
* value is false.
|
||||
*/
|
||||
pagingEnabled: nativePropType(PropTypes.bool),
|
||||
pagingEnabled: PropTypes.bool,
|
||||
/**
|
||||
* When true, the scroll view scrolls to top when the status bar is tapped.
|
||||
* The default value is true.
|
||||
*/
|
||||
scrollsToTop: nativePropType(PropTypes.bool),
|
||||
scrollsToTop: PropTypes.bool,
|
||||
/**
|
||||
* An array of child indices determining which children get docked to the
|
||||
* top of the screen when scrolling. For example, passing
|
||||
|
@ -142,7 +164,7 @@ var ScrollView = React.createClass({
|
|||
* top of the scroll view. This property is not supported in conjunction
|
||||
* with `horizontal={true}`.
|
||||
*/
|
||||
stickyHeaderIndices: nativePropType(ArrayOfPropType(PropTypes.number)),
|
||||
stickyHeaderIndices: PropTypes.arrayOf(PropTypes.number),
|
||||
/**
|
||||
* Experimental: When true, offscreen child views (whose `overflow` value is
|
||||
* `hidden`) are removed from their native backing superview when offscreen.
|
||||
|
@ -153,7 +175,7 @@ var ScrollView = React.createClass({
|
|||
/**
|
||||
* The current scale of the scroll view content. The default value is 1.0.
|
||||
*/
|
||||
zoomScale: nativePropType(PropTypes.number),
|
||||
zoomScale: PropTypes.number,
|
||||
},
|
||||
|
||||
mixins: [ScrollResponder.Mixin],
|
||||
|
@ -171,7 +193,11 @@ var ScrollView = React.createClass({
|
|||
},
|
||||
|
||||
scrollTo: function(destY, destX) {
|
||||
RKUIManager.scrollTo(ReactIOSTagHandles.rootNodeIDToTag[this._rootNodeID], destX, destY);
|
||||
RKUIManager.scrollTo(
|
||||
ReactIOSTagHandles.rootNodeIDToTag[this._rootNodeID],
|
||||
destX || 0,
|
||||
destY || 0
|
||||
);
|
||||
},
|
||||
|
||||
render: function() {
|
||||
|
@ -223,36 +249,47 @@ var ScrollView = React.createClass({
|
|||
this.props.alwaysBounceVertical :
|
||||
!this.props.horizontal;
|
||||
|
||||
var props = merge(
|
||||
this.props, {
|
||||
alwaysBounceHorizontal,
|
||||
alwaysBounceVertical,
|
||||
keyboardDismissMode: this.props.keyboardDismissMode ?
|
||||
keyboardDismissModeConstants[this.props.keyboardDismissMode] :
|
||||
undefined,
|
||||
style: [styles.base, this.props.style],
|
||||
onTouchStart: this.scrollResponderHandleTouchStart,
|
||||
onTouchMove: this.scrollResponderHandleTouchMove,
|
||||
onTouchEnd: this.scrollResponderHandleTouchEnd,
|
||||
onScrollBeginDrag: this.scrollResponderHandleScrollBeginDrag,
|
||||
onScrollEndDrag: this.scrollResponderHandleScrollEndDrag,
|
||||
onMomentumScrollBegin: this.scrollResponderHandleMomentumScrollBegin,
|
||||
onMomentumScrollEnd: this.scrollResponderHandleMomentumScrollEnd,
|
||||
onStartShouldSetResponder: this.scrollResponderHandleStartShouldSetResponder,
|
||||
onStartShouldSetResponderCapture: this.scrollResponderHandleStartShouldSetResponderCapture,
|
||||
onScrollShouldSetResponder: this.scrollResponderHandleScrollShouldSetResponder,
|
||||
onScroll: this.scrollResponderHandleScroll,
|
||||
onResponderGrant: this.scrollResponderHandleResponderGrant,
|
||||
onResponderTerminationRequest: this.scrollResponderHandleTerminationRequest,
|
||||
onResponderTerminate: this.scrollResponderHandleTerminate,
|
||||
onResponderRelease: this.scrollResponderHandleResponderRelease,
|
||||
onResponderReject: this.scrollResponderHandleResponderReject,
|
||||
var props = {
|
||||
...this.props,
|
||||
alwaysBounceHorizontal,
|
||||
alwaysBounceVertical,
|
||||
keyboardDismissMode: this.props.keyboardDismissMode ?
|
||||
keyboardDismissModeConstants[this.props.keyboardDismissMode] :
|
||||
undefined,
|
||||
style: [styles.base, this.props.style],
|
||||
onTouchStart: this.scrollResponderHandleTouchStart,
|
||||
onTouchMove: this.scrollResponderHandleTouchMove,
|
||||
onTouchEnd: this.scrollResponderHandleTouchEnd,
|
||||
onScrollBeginDrag: this.scrollResponderHandleScrollBeginDrag,
|
||||
onScrollEndDrag: this.scrollResponderHandleScrollEndDrag,
|
||||
onMomentumScrollBegin: this.scrollResponderHandleMomentumScrollBegin,
|
||||
onMomentumScrollEnd: this.scrollResponderHandleMomentumScrollEnd,
|
||||
onStartShouldSetResponder: this.scrollResponderHandleStartShouldSetResponder,
|
||||
onStartShouldSetResponderCapture: this.scrollResponderHandleStartShouldSetResponderCapture,
|
||||
onScrollShouldSetResponder: this.scrollResponderHandleScrollShouldSetResponder,
|
||||
onScroll: this.scrollResponderHandleScroll,
|
||||
onResponderGrant: this.scrollResponderHandleResponderGrant,
|
||||
onResponderTerminationRequest: this.scrollResponderHandleTerminationRequest,
|
||||
onResponderTerminate: this.scrollResponderHandleTerminate,
|
||||
onResponderRelease: this.scrollResponderHandleResponderRelease,
|
||||
onResponderReject: this.scrollResponderHandleResponderReject,
|
||||
};
|
||||
|
||||
var ScrollViewClass;
|
||||
if (Platform.OS === 'ios') {
|
||||
ScrollViewClass = RCTScrollView;
|
||||
} else if (Platform.OS === 'android') {
|
||||
if (this.props.horizontal) {
|
||||
ScrollViewClass = AndroidHorizontalScrollView;
|
||||
} else {
|
||||
ScrollViewClass = AndroidScrollView;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<RKScrollView {...props} ref={SCROLLVIEW}>
|
||||
<ScrollViewClass {...props} ref={SCROLLVIEW}>
|
||||
{contentContainer}
|
||||
</RKScrollView>
|
||||
</ScrollViewClass>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
@ -267,12 +304,46 @@ var styles = StyleSheet.create({
|
|||
},
|
||||
});
|
||||
|
||||
var RKScrollView = createReactIOSNativeComponentClass({
|
||||
validAttributes: merge(
|
||||
ReactIOSViewAttributes.UIView,
|
||||
validAttributesFromPropTypes(ScrollView.propTypes)
|
||||
),
|
||||
uiViewClassName: 'RCTScrollView',
|
||||
});
|
||||
var validAttributes = {
|
||||
...ReactIOSViewAttributes.UIView,
|
||||
alwaysBounceHorizontal: true,
|
||||
alwaysBounceVertical: true,
|
||||
automaticallyAdjustContentInsets: true,
|
||||
centerContent: true,
|
||||
contentInset: insetsDiffer,
|
||||
contentOffset: pointsDiffer,
|
||||
decelerationRate: true,
|
||||
horizontal: true,
|
||||
keyboardDismissMode: true,
|
||||
keyboardShouldPersistTaps: true,
|
||||
maximumZoomScale: true,
|
||||
minimumZoomScale: true,
|
||||
pagingEnabled: true,
|
||||
removeClippedSubviews: true,
|
||||
scrollEnabled: true,
|
||||
scrollIndicatorInsets: insetsDiffer,
|
||||
scrollsToTop: true,
|
||||
showsHorizontalScrollIndicator: true,
|
||||
showsVerticalScrollIndicator: true,
|
||||
stickyHeaderIndices: deepDiffer,
|
||||
throttleScrollCallbackMS: true,
|
||||
zoomScale: true,
|
||||
};
|
||||
|
||||
if (Platform.OS === 'android') {
|
||||
var AndroidScrollView = createReactIOSNativeComponentClass({
|
||||
validAttributes: validAttributes,
|
||||
uiViewClassName: 'AndroidScrollView',
|
||||
});
|
||||
var AndroidHorizontalScrollView = createReactIOSNativeComponentClass({
|
||||
validAttributes: validAttributes,
|
||||
uiViewClassName: 'AndroidHorizontalScrollView',
|
||||
});
|
||||
} else if (Platform.OS === 'ios') {
|
||||
var RCTScrollView = createReactIOSNativeComponentClass({
|
||||
validAttributes: validAttributes,
|
||||
uiViewClassName: 'RCTScrollView',
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = ScrollView;
|
|
@ -1,30 +0,0 @@
|
|||
/**
|
||||
* Copyright 2004-present Facebook. All Rights Reserved.
|
||||
*
|
||||
* @providesModule ScrollViewPropTypes
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var EdgeInsetsPropType = require('EdgeInsetsPropType');
|
||||
var PointPropType = require('PointPropType');
|
||||
var PropTypes = require('ReactPropTypes');
|
||||
var StyleSheetPropType = require('StyleSheetPropType');
|
||||
var ViewStylePropTypes = require('ViewStylePropTypes');
|
||||
|
||||
var nativePropType = require('nativePropType');
|
||||
|
||||
var ScrollViewPropTypes = {
|
||||
automaticallyAdjustContentInsets: nativePropType(PropTypes.bool), // true
|
||||
contentInset: nativePropType(EdgeInsetsPropType), // zeroes
|
||||
contentOffset: nativePropType(PointPropType), // zeroes
|
||||
onScroll: PropTypes.func,
|
||||
onScrollAnimationEnd: PropTypes.func,
|
||||
scrollEnabled: nativePropType(PropTypes.bool), // true
|
||||
scrollIndicatorInsets: nativePropType(EdgeInsetsPropType), // zeros
|
||||
showsHorizontalScrollIndicator: nativePropType(PropTypes.bool),
|
||||
showsVerticalScrollIndicator: nativePropType(PropTypes.bool),
|
||||
style: StyleSheetPropType(ViewStylePropTypes),
|
||||
throttleScrollCallbackMS: nativePropType(PropTypes.number), // null
|
||||
};
|
||||
|
||||
module.exports = ScrollViewPropTypes;
|
|
@ -0,0 +1,83 @@
|
|||
/**
|
||||
* Copyright 2004-present Facebook. All Rights Reserved.
|
||||
*
|
||||
* @providesModule Slider
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var NativeMethodsMixin = require('NativeMethodsMixin');
|
||||
var PropTypes = require('ReactPropTypes');
|
||||
var React = require('React');
|
||||
var ReactIOSViewAttributes = require('ReactIOSViewAttributes');
|
||||
var StyleSheet = require('StyleSheet');
|
||||
var View = require('View');
|
||||
|
||||
var createReactIOSNativeComponentClass =
|
||||
require('createReactIOSNativeComponentClass');
|
||||
var merge = require('merge');
|
||||
|
||||
var Slider = React.createClass({
|
||||
mixins: [NativeMethodsMixin],
|
||||
|
||||
propTypes: {
|
||||
/**
|
||||
* Used to style and layout the `Slider`. See `StyleSheet.js` and
|
||||
* `ViewStylePropTypes.js` for more info.
|
||||
*/
|
||||
style: View.propTypes.style,
|
||||
|
||||
/**
|
||||
* Initial value of the slider. The value should be between 0 and 1.
|
||||
* Default value is 0.
|
||||
*
|
||||
* *This is not a controlled component*, e.g. if you don't update
|
||||
* the value, the component won't be reseted to it's inital value.
|
||||
*/
|
||||
value: PropTypes.number,
|
||||
|
||||
/**
|
||||
* Callback continuously called while the user is dragging the slider.
|
||||
*/
|
||||
onValueChange: PropTypes.func,
|
||||
|
||||
/**
|
||||
* Callback called when the user finishes changing the value (e.g. when
|
||||
* the slider is released).
|
||||
*/
|
||||
onSlidingComplete: PropTypes.func,
|
||||
},
|
||||
|
||||
_onValueChange: function(event) {
|
||||
this.props.onChange && this.props.onChange(event);
|
||||
if (event.nativeEvent.continuous) {
|
||||
this.props.onValueChange &&
|
||||
this.props.onValueChange(event.nativeEvent.value);
|
||||
} else {
|
||||
this.props.onSlidingComplete && event.nativeEvent.value !== undefined &&
|
||||
this.props.onSlidingComplete(event.nativeEvent.value);
|
||||
}
|
||||
},
|
||||
|
||||
render: function() {
|
||||
return (
|
||||
<RKSlider
|
||||
style={[styles.slider, this.props.style]}
|
||||
value={this.props.value}
|
||||
onChange={this._onValueChange}
|
||||
/>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
var styles = StyleSheet.create({
|
||||
slider: {
|
||||
height: 40,
|
||||
},
|
||||
});
|
||||
|
||||
var RKSlider = createReactIOSNativeComponentClass({
|
||||
validAttributes: merge(ReactIOSViewAttributes.UIView, {value: true}),
|
||||
uiViewClassName: 'RCTSlider',
|
||||
});
|
||||
|
||||
module.exports = Slider;
|
|
@ -0,0 +1,41 @@
|
|||
/**
|
||||
* Copyright 2004-present Facebook. All Rights Reserved.
|
||||
*
|
||||
* @providesModule SwitchIOS
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var React = require('React');
|
||||
var StyleSheet = require('StyleSheet');
|
||||
var Text = require('Text');
|
||||
var View = require('View');
|
||||
|
||||
var DummySwitchIOS = React.createClass({
|
||||
render: function() {
|
||||
return (
|
||||
<View style={[styles.dummySwitchIOS, this.props.style]}>
|
||||
<Text style={styles.text}>SwitchIOS is not supported on this platform!</Text>
|
||||
</View>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
var styles = StyleSheet.create({
|
||||
dummySwitchIOS: {
|
||||
width: 120,
|
||||
height: 50,
|
||||
backgroundColor: '#ffbcbc',
|
||||
borderWidth: 1,
|
||||
borderColor: 'red',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
text: {
|
||||
color: '#333333',
|
||||
margin: 5,
|
||||
fontSize: 10,
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = DummySwitchIOS;
|
|
@ -0,0 +1,117 @@
|
|||
/**
|
||||
* Copyright 2004-present Facebook. All Rights Reserved.
|
||||
*
|
||||
* @providesModule SwitchIOS
|
||||
*
|
||||
* This is a controlled component version of RKSwitch.
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var NativeMethodsMixin = require('NativeMethodsMixin');
|
||||
var PropTypes = require('ReactPropTypes');
|
||||
var React = require('React');
|
||||
var ReactIOSViewAttributes = require('ReactIOSViewAttributes');
|
||||
var StyleSheet = require('StyleSheet');
|
||||
|
||||
var createReactIOSNativeComponentClass = require('createReactIOSNativeComponentClass');
|
||||
var merge = require('merge');
|
||||
|
||||
var SWITCH = 'switch';
|
||||
|
||||
/**
|
||||
* Use `SwitchIOS` to render a boolean input on iOS. This is
|
||||
* a controlled component, so you must hook in to the `onValueChange` callback
|
||||
* and update the `value` prop in order for the component to update, otherwise
|
||||
* the user's change will be reverted immediately to reflect `props.value` as the
|
||||
* source of truth.
|
||||
*/
|
||||
var SwitchIOS = React.createClass({
|
||||
mixins: [NativeMethodsMixin],
|
||||
|
||||
propTypes: {
|
||||
/**
|
||||
* The value of the switch, if true the switch will be turned on.
|
||||
* Default value is false.
|
||||
*/
|
||||
value: PropTypes.bool,
|
||||
|
||||
/**
|
||||
* If true the user won't be able to toggle the switch.
|
||||
* Default value is false.
|
||||
*/
|
||||
disabled: PropTypes.bool,
|
||||
|
||||
/**
|
||||
* Callback that is called when the user toggles the switch.
|
||||
*/
|
||||
onValueChange: PropTypes.func,
|
||||
|
||||
/**
|
||||
* Background color when the switch is turned on.
|
||||
*/
|
||||
onTintColor: PropTypes.string,
|
||||
|
||||
/**
|
||||
* Background color for the switch round button.
|
||||
*/
|
||||
thumbTintColor: PropTypes.string,
|
||||
|
||||
/**
|
||||
* Background color when the switch is turned off.
|
||||
*/
|
||||
tintColor: PropTypes.string,
|
||||
},
|
||||
|
||||
getDefaultProps: function() {
|
||||
return {
|
||||
value: false,
|
||||
disabled: false,
|
||||
};
|
||||
},
|
||||
|
||||
_onChange: function(event) {
|
||||
this.props.onChange && this.props.onChange(event);
|
||||
this.props.onValueChange && this.props.onValueChange(event.nativeEvent.value);
|
||||
|
||||
// The underlying switch might have changed, but we're controlled,
|
||||
// and so want to ensure it represents our value.
|
||||
this.refs[SWITCH].setNativeProps({on: this.props.value});
|
||||
},
|
||||
|
||||
render: function() {
|
||||
return (
|
||||
<RKSwitch
|
||||
ref={SWITCH}
|
||||
style={[styles.rkSwitch, this.props.style]}
|
||||
enabled={!this.props.disabled}
|
||||
on={this.props.value}
|
||||
onChange={this._onChange}
|
||||
onTintColor={this.props.onTintColor}
|
||||
thumbTintColor={this.props.thumbTintColor}
|
||||
tintColor={this.props.tintColor}
|
||||
/>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
var styles = StyleSheet.create({
|
||||
rkSwitch: {
|
||||
height: 31,
|
||||
width: 51,
|
||||
},
|
||||
});
|
||||
|
||||
var rkSwitchAttributes = merge(ReactIOSViewAttributes.UIView, {
|
||||
onTintColor: true,
|
||||
tintColor: true,
|
||||
thumbTintColor: true,
|
||||
on: true,
|
||||
enabled: true,
|
||||
});
|
||||
|
||||
var RKSwitch = createReactIOSNativeComponentClass({
|
||||
validAttributes: rkSwitchAttributes,
|
||||
uiViewClassName: 'RCTSwitch',
|
||||
});
|
||||
|
||||
module.exports = SwitchIOS;
|
|
@ -18,12 +18,12 @@ var merge = require('merge');
|
|||
|
||||
var TabBarItemIOS = React.createClass({
|
||||
propTypes: {
|
||||
icon: Image.sourcePropType.isRequired,
|
||||
icon: Image.propTypes.source.isRequired,
|
||||
onPress: React.PropTypes.func.isRequired,
|
||||
selected: React.PropTypes.bool.isRequired,
|
||||
badgeValue: React.PropTypes.string,
|
||||
title: React.PropTypes.string,
|
||||
style: View.stylePropType,
|
||||
style: View.propTypes.style,
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
|
|
|
@ -26,39 +26,6 @@ var getObjectValues = require('getObjectValues');
|
|||
var invariant = require('invariant');
|
||||
var merge = require('merge');
|
||||
|
||||
/**
|
||||
* <TextInput> - A foundational component for inputting text into the app via a
|
||||
* keyboard. Props provide configurability for several features, such as auto-
|
||||
* correction, auto-capitalization, placeholder text, and different keyboard
|
||||
* types, such as a numeric keypad.
|
||||
*
|
||||
* The simplest use case is to plop down a `TextInput` and subscribe to the
|
||||
* `onChangeText` events to read the user input. There are also other events, such
|
||||
* as `onSubmitEditing` and `onFocus` that can be subscribed to. A simple
|
||||
* example:
|
||||
*
|
||||
* <View>
|
||||
* <TextInput
|
||||
* style={{height: 40, borderColor: 'gray', borderWidth: 1}}
|
||||
* onChangeText={(text) => this.setState({input: text})}
|
||||
* />
|
||||
* <Text>{'user input: ' + this.state.input}</Text>
|
||||
* </View>
|
||||
*
|
||||
* The `value` prop can be used to set the value of the input in order to make
|
||||
* the state of the component clear, but <TextInput> does not behave as a true
|
||||
* controlled component by default because all operations are asynchronous.
|
||||
* Setting `value` once is like setting the default value, but you can change it
|
||||
* continuously based on `onChangeText` events as well. If you really want to
|
||||
* force the component to always revert to the value you are setting, you can
|
||||
* set `controlled={true}`.
|
||||
*
|
||||
* The `multiline` prop is not supported in all releases, and some props are
|
||||
* multiline only.
|
||||
*
|
||||
* More example code in `TextInputExample.js`.
|
||||
*/
|
||||
|
||||
var autoCapitalizeConsts = RKUIManager.UIText.AutocapitalizationType;
|
||||
var clearButtonModeConsts = RKUIManager.UITextField.clearButtonMode;
|
||||
|
||||
|
@ -92,6 +59,39 @@ var notMultiline = {
|
|||
onSubmitEditing: true,
|
||||
};
|
||||
|
||||
/**
|
||||
* A foundational component for inputting text into the app via a
|
||||
* keyboard. Props provide configurability for several features, such as auto-
|
||||
* correction, auto-capitalization, placeholder text, and different keyboard
|
||||
* types, such as a numeric keypad.
|
||||
*
|
||||
* The simplest use case is to plop down a `TextInput` and subscribe to the
|
||||
* `onChangeText` events to read the user input. There are also other events, such
|
||||
* as `onSubmitEditing` and `onFocus` that can be subscribed to. A simple
|
||||
* example:
|
||||
*
|
||||
* ```
|
||||
* <View>
|
||||
* <TextInput
|
||||
* style={{height: 40, borderColor: 'gray', borderWidth: 1}}
|
||||
* onChangeText={(text) => this.setState({input: text})}
|
||||
* />
|
||||
* <Text>{'user input: ' + this.state.input}</Text>
|
||||
* </View>
|
||||
* ```
|
||||
*
|
||||
* The `value` prop can be used to set the value of the input in order to make
|
||||
* the state of the component clear, but <TextInput> does not behave as a true
|
||||
* controlled component by default because all operations are asynchronous.
|
||||
* Setting `value` once is like setting the default value, but you can change it
|
||||
* continuously based on `onChangeText` events as well. If you really want to
|
||||
* force the component to always revert to the value you are setting, you can
|
||||
* set `controlled={true}`.
|
||||
*
|
||||
* The `multiline` prop is not supported in all releases, and some props are
|
||||
* multiline only.
|
||||
*/
|
||||
|
||||
var TextInput = React.createClass({
|
||||
propTypes: {
|
||||
/**
|
||||
|
@ -188,7 +188,7 @@ var TextInput = React.createClass({
|
|||
'always',
|
||||
]),
|
||||
|
||||
style: Text.stylePropType,
|
||||
style: Text.propTypes.style,
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -20,35 +20,35 @@ var keyOf = require('keyOf');
|
|||
var merge = require('merge');
|
||||
var onlyChild = require('onlyChild');
|
||||
|
||||
var DEFAULT_PROPS = {
|
||||
activeOpacity: 0.8,
|
||||
underlayColor: 'black',
|
||||
};
|
||||
|
||||
/**
|
||||
* TouchableHighlight - A wrapper for making views respond properly to touches.
|
||||
* A wrapper for making views respond properly to touches.
|
||||
* On press down, the opacity of the wrapped view is decreased, which allows
|
||||
* the underlay color to show through, darkening or tinting the view. The
|
||||
* underlay comes from adding a view to the view hierarchy, which can sometimes
|
||||
* cause unwanted visual artifacts if not used correctly, for example if the
|
||||
* backgroundColor of the wrapped view isn't explicitly set to an opaque color.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* renderButton: function() {
|
||||
* return (
|
||||
* <TouchableHighlight onPress={this._onPressButton}>
|
||||
* <Image
|
||||
* style={styles.button}
|
||||
* source={ix('myButton')}
|
||||
* />
|
||||
* </View>
|
||||
* );
|
||||
* },
|
||||
*
|
||||
* More example code in TouchableExample.js, and more in-depth discussion in
|
||||
* Touchable.js. See also TouchableWithoutFeedback.js.
|
||||
* ```
|
||||
* renderButton: function() {
|
||||
* return (
|
||||
* <TouchableHighlight onPress={this._onPressButton}>
|
||||
* <Image
|
||||
* style={styles.button}
|
||||
* source={ix('myButton')}
|
||||
* />
|
||||
* </View>
|
||||
* );
|
||||
* },
|
||||
* ```
|
||||
*/
|
||||
|
||||
var DEFAULT_PROPS = {
|
||||
activeOpacity: 0.8,
|
||||
underlayColor: 'black',
|
||||
};
|
||||
|
||||
var TouchableHighlight = React.createClass({
|
||||
propTypes: {
|
||||
...TouchableFeedbackPropType,
|
||||
|
@ -67,7 +67,7 @@ var TouchableHighlight = React.createClass({
|
|||
* active.
|
||||
*/
|
||||
underlayColor: React.PropTypes.string,
|
||||
style: View.stylePropType,
|
||||
style: View.propTypes.style,
|
||||
},
|
||||
|
||||
mixins: [NativeMethodsMixin, TimerMixin, Touchable.Mixin],
|
||||
|
|
|
@ -17,25 +17,25 @@ var keyOf = require('keyOf');
|
|||
var onlyChild = require('onlyChild');
|
||||
|
||||
/**
|
||||
* TouchableOpacity - A wrapper for making views respond properly to touches.
|
||||
* A wrapper for making views respond properly to touches.
|
||||
* On press down, the opacity of the wrapped view is decreased, dimming it.
|
||||
* This is done without actually changing the view hierarchy, and in general is
|
||||
* easy to add to an app without weird side-effects. Example:
|
||||
* easy to add to an app without weird side-effects.
|
||||
*
|
||||
* renderButton: function() {
|
||||
* return (
|
||||
* <TouchableOpacity onPress={this._onPressButton}>
|
||||
* <Image
|
||||
* style={styles.button}
|
||||
* source={ix('myButton')}
|
||||
* />
|
||||
* </View>
|
||||
* );
|
||||
* },
|
||||
* Example:
|
||||
*
|
||||
* More example code in TouchableExample.js, and more in-depth discussion in
|
||||
* Touchable.js. See also TouchableHighlight.js and
|
||||
* TouchableWithoutFeedback.js.
|
||||
* ```
|
||||
* renderButton: function() {
|
||||
* return (
|
||||
* <TouchableOpacity onPress={this._onPressButton}>
|
||||
* <Image
|
||||
* style={styles.button}
|
||||
* source={ix('myButton')}
|
||||
* />
|
||||
* </View>
|
||||
* );
|
||||
* },
|
||||
* ```
|
||||
*/
|
||||
|
||||
var TouchableOpacity = React.createClass({
|
||||
|
|
|
@ -12,8 +12,13 @@ var ReactIOSViewAttributes = require('ReactIOSViewAttributes');
|
|||
var StyleSheetPropType = require('StyleSheetPropType');
|
||||
var ViewStylePropTypes = require('ViewStylePropTypes');
|
||||
|
||||
|
||||
var createReactIOSNativeComponentClass = require('createReactIOSNativeComponentClass');
|
||||
|
||||
var stylePropType = StyleSheetPropType(ViewStylePropTypes);
|
||||
|
||||
/**
|
||||
* <View> - The most fundamental component for building UI, `View` is a
|
||||
* The most fundamental component for building UI, `View` is a
|
||||
* container that supports layout with flexbox, style, some touch handling, and
|
||||
* accessibility controls, and is designed to be nested inside other views and
|
||||
* to have 0 to many children of any type. `View` maps directly to the native
|
||||
|
@ -21,11 +26,13 @@ var ViewStylePropTypes = require('ViewStylePropTypes');
|
|||
* `UIView`, `<div>`, `android.view`, etc. This example creates a `View` that
|
||||
* wraps two colored boxes and custom component in a row with padding.
|
||||
*
|
||||
* <View style={{flexDirection: 'row', height: 100, padding: 20}}>
|
||||
* <View style={{backgroundColor: 'blue', flex: 0.3}} />
|
||||
* <View style={{backgroundColor: 'red', flex: 0.5}} />
|
||||
* <MyCustomComponent {...customProps} />
|
||||
* </View>
|
||||
* ```
|
||||
* <View style={{flexDirection: 'row', height: 100, padding: 20}}>
|
||||
* <View style={{backgroundColor: 'blue', flex: 0.3}} />
|
||||
* <View style={{backgroundColor: 'red', flex: 0.5}} />
|
||||
* <MyCustomComponent {...customProps} />
|
||||
* </View>
|
||||
* ```
|
||||
*
|
||||
* By default, `View`s have a primary flex direction of 'column', so children
|
||||
* will stack up vertically by default. `View`s also expand to fill the parent
|
||||
|
@ -39,20 +46,8 @@ var ViewStylePropTypes = require('ViewStylePropTypes');
|
|||
* `View`s are designed to be used with `StyleSheet`s for clarity and
|
||||
* performance, although inline styles are also supported. It is common for
|
||||
* `StyleSheet`s to be combined dynamically. See `StyleSheet.js` for more info.
|
||||
*
|
||||
* Check out `ViewExample.js`, `LayoutExample.js`, and other apps for more code
|
||||
* examples.
|
||||
*/
|
||||
|
||||
var createReactIOSNativeComponentClass = require('createReactIOSNativeComponentClass');
|
||||
|
||||
var stylePropType = StyleSheetPropType(ViewStylePropTypes);
|
||||
|
||||
var View = React.createClass({
|
||||
statics: {
|
||||
stylePropType,
|
||||
},
|
||||
|
||||
mixins: [NativeMethodsMixin],
|
||||
|
||||
/**
|
||||
|
@ -141,12 +136,12 @@ var RKView = createReactIOSNativeComponentClass({
|
|||
validAttributes: ReactIOSViewAttributes.RKView,
|
||||
uiViewClassName: 'RCTView',
|
||||
});
|
||||
RKView.propTypes = View.propTypes;
|
||||
|
||||
var ViewToExport = RKView;
|
||||
if (__DEV__) {
|
||||
ViewToExport = View;
|
||||
}
|
||||
|
||||
ViewToExport.stylePropType = stylePropType;
|
||||
|
||||
module.exports = ViewToExport;
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
/**
|
||||
* Copyright 2004-present Facebook. All Rights Reserved.
|
||||
*
|
||||
* @providesModule GeoLocation
|
||||
* @providesModule Geolocation
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var RCTDeviceEventEmitter = require('RCTDeviceEventEmitter');
|
||||
var RCTLocationObserver = require('NativeModules').RKLocationObserver;
|
||||
var RCTLocationObserver = require('NativeModulesDeprecated').RKLocationObserver;
|
||||
|
||||
var invariant = require('invariant');
|
||||
var logError = require('logError');
|
||||
|
@ -16,13 +16,6 @@ var subscriptions = [];
|
|||
|
||||
var updatesEnabled = false;
|
||||
|
||||
var ensureObserving = function() {
|
||||
if (!updatesEnabled) {
|
||||
RCTLocationObserver.startObserving();
|
||||
updatesEnabled = true;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* /!\ ATTENTION /!\
|
||||
* You need to add NSLocationWhenInUseUsageDescription key
|
||||
|
@ -30,43 +23,51 @@ var ensureObserving = function() {
|
|||
* to *fail silently*!
|
||||
* \!/ \!/
|
||||
*
|
||||
* GeoLocation follows the MDN specification:
|
||||
* Geolocation follows the MDN specification:
|
||||
* https://developer.mozilla.org/en-US/docs/Web/API/Geolocation
|
||||
*/
|
||||
class GeoLocation {
|
||||
static getCurrentPosition(geo_success, geo_error, geo_options) {
|
||||
var Geolocation = {
|
||||
|
||||
getCurrentPosition: function(geo_success, geo_error, geo_options) {
|
||||
invariant(
|
||||
typeof geo_success === 'function',
|
||||
'Must provide a valid geo_success callback.'
|
||||
);
|
||||
if (geo_options) {
|
||||
warning('geo_options are not yet supported.');
|
||||
}
|
||||
ensureObserving();
|
||||
RCTLocationObserver.getCurrentPosition(
|
||||
geo_success,
|
||||
geo_error || logError
|
||||
geo_error || logError,
|
||||
geo_options || {}
|
||||
);
|
||||
}
|
||||
static watchPosition(callback) {
|
||||
ensureObserving();
|
||||
},
|
||||
|
||||
watchPosition: function(success, error, options) {
|
||||
if (!updatesEnabled) {
|
||||
RCTLocationObserver.startObserving(options || {});
|
||||
updatesEnabled = true;
|
||||
}
|
||||
var watchID = subscriptions.length;
|
||||
subscriptions.push(
|
||||
subscriptions.push([
|
||||
RCTDeviceEventEmitter.addListener(
|
||||
'geoLocationDidChange',
|
||||
callback
|
||||
)
|
||||
);
|
||||
'geolocationDidChange',
|
||||
success
|
||||
),
|
||||
error ? RCTDeviceEventEmitter.addListener(
|
||||
'geolocationError',
|
||||
error
|
||||
) : null,
|
||||
]);
|
||||
return watchID;
|
||||
}
|
||||
static clearWatch(watchID) {
|
||||
},
|
||||
|
||||
clearWatch: function(watchID) {
|
||||
var sub = subscriptions[watchID];
|
||||
if (!sub) {
|
||||
// Silently exit when the watchID is invalid or already cleared
|
||||
// This is consistent with timers
|
||||
return;
|
||||
}
|
||||
sub.remove();
|
||||
sub[0].remove();
|
||||
sub[1] && sub[1].remove();
|
||||
subscriptions[watchID] = undefined;
|
||||
var noWatchers = true;
|
||||
for (var ii = 0; ii < subscriptions.length; ii++) {
|
||||
|
@ -75,10 +76,11 @@ class GeoLocation {
|
|||
}
|
||||
}
|
||||
if (noWatchers) {
|
||||
GeoLocation.stopObserving();
|
||||
Geolocation.stopObserving();
|
||||
}
|
||||
}
|
||||
static stopObserving() {
|
||||
},
|
||||
|
||||
stopObserving: function() {
|
||||
if (updatesEnabled) {
|
||||
RCTLocationObserver.stopObserving();
|
||||
updatesEnabled = false;
|
||||
|
@ -89,10 +91,8 @@ class GeoLocation {
|
|||
}
|
||||
}
|
||||
subscriptions = [];
|
||||
} else {
|
||||
warning('Tried to stop observing when not observing.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = GeoLocation;
|
||||
module.exports = Geolocation;
|
|
@ -0,0 +1,256 @@
|
|||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 46;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
134814061AA4E45400B7C361 /* RCTLocationObserver.m in Sources */ = {isa = PBXBuildFile; fileRef = 134814051AA4E45400B7C361 /* RCTLocationObserver.m */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
58B511D91A9E6C8500147676 /* CopyFiles */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
dstPath = "include/$(PRODUCT_NAME)";
|
||||
dstSubfolderSpec = 16;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
134814041AA4E45400B7C361 /* RCTLocationObserver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTLocationObserver.h; sourceTree = "<group>"; };
|
||||
134814051AA4E45400B7C361 /* RCTLocationObserver.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTLocationObserver.m; sourceTree = "<group>"; };
|
||||
134814201AA4EA6300B7C361 /* libRCTGeolocation.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRCTGeolocation.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
58B511D81A9E6C8500147676 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
134814211AA4EA7D00B7C361 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
134814201AA4EA6300B7C361 /* libRCTGeolocation.a */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
58B511D21A9E6C8500147676 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
134814041AA4E45400B7C361 /* RCTLocationObserver.h */,
|
||||
134814051AA4E45400B7C361 /* RCTLocationObserver.m */,
|
||||
134814211AA4EA7D00B7C361 /* Products */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
58B511DA1A9E6C8500147676 /* RCTGeolocation */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "RCTGeolocation" */;
|
||||
buildPhases = (
|
||||
58B511D71A9E6C8500147676 /* Sources */,
|
||||
58B511D81A9E6C8500147676 /* Frameworks */,
|
||||
58B511D91A9E6C8500147676 /* CopyFiles */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = RCTGeolocation;
|
||||
productName = RCTDataManager;
|
||||
productReference = 134814201AA4EA6300B7C361 /* libRCTGeolocation.a */;
|
||||
productType = "com.apple.product-type.library.static";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
58B511D31A9E6C8500147676 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 0610;
|
||||
ORGANIZATIONNAME = Facebook;
|
||||
TargetAttributes = {
|
||||
58B511DA1A9E6C8500147676 = {
|
||||
CreatedOnToolsVersion = 6.1.1;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "RCTGeolocation" */;
|
||||
compatibilityVersion = "Xcode 3.2";
|
||||
developmentRegion = English;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
);
|
||||
mainGroup = 58B511D21A9E6C8500147676;
|
||||
productRefGroup = 58B511D21A9E6C8500147676;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
58B511DA1A9E6C8500147676 /* RCTGeolocation */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
58B511D71A9E6C8500147676 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
134814061AA4E45400B7C361 /* RCTLocationObserver.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
58B511ED1A9E6C8500147676 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.1;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
58B511EE1A9E6C8500147676 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = YES;
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.1;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
58B511F01A9E6C8500147676 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
|
||||
"$(SRCROOT)/../../ReactKit/**",
|
||||
);
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"/Users/nicklockwood/fbobjc-hg/Libraries/FBReactKit/js/react-native-github/ReactKit/build/Debug-iphoneos",
|
||||
);
|
||||
OTHER_LDFLAGS = "-ObjC";
|
||||
PRODUCT_NAME = RCTGeolocation;
|
||||
SKIP_INSTALL = YES;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
58B511F11A9E6C8500147676 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
|
||||
"$(SRCROOT)/../../ReactKit/**",
|
||||
);
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"/Users/nicklockwood/fbobjc-hg/Libraries/FBReactKit/js/react-native-github/ReactKit/build/Debug-iphoneos",
|
||||
);
|
||||
OTHER_LDFLAGS = "-ObjC";
|
||||
PRODUCT_NAME = RCTGeolocation;
|
||||
SKIP_INSTALL = YES;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "RCTGeolocation" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
58B511ED1A9E6C8500147676 /* Debug */,
|
||||
58B511EE1A9E6C8500147676 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "RCTGeolocation" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
58B511F01A9E6C8500147676 /* Debug */,
|
||||
58B511F11A9E6C8500147676 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = 58B511D31A9E6C8500147676 /* Project object */;
|
||||
}
|
|
@ -0,0 +1,319 @@
|
|||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#import "RCTLocationObserver.h"
|
||||
|
||||
#import <CoreLocation/CLError.h>
|
||||
#import <CoreLocation/CLLocationManager.h>
|
||||
#import <CoreLocation/CLLocationManagerDelegate.h>
|
||||
|
||||
#import "RCTAssert.h"
|
||||
#import "RCTBridge.h"
|
||||
#import "RCTConvert.h"
|
||||
#import "RCTEventDispatcher.h"
|
||||
#import "RCTLog.h"
|
||||
|
||||
typedef NS_ENUM(NSInteger, RCTPositionErrorCode) {
|
||||
RCTPositionErrorDenied = 1,
|
||||
RCTPositionErrorUnavailable,
|
||||
RCTPositionErrorTimeout,
|
||||
};
|
||||
|
||||
#define RCT_DEFAULT_LOCATION_ACCURACY kCLLocationAccuracyHundredMeters
|
||||
|
||||
typedef struct {
|
||||
NSTimeInterval timeout;
|
||||
NSTimeInterval maximumAge;
|
||||
CLLocationAccuracy accuracy;
|
||||
} RCTLocationOptions;
|
||||
|
||||
static RCTLocationOptions RCTLocationOptionsWithJSON(id json)
|
||||
{
|
||||
NSDictionary *options = [RCTConvert NSDictionary:json];
|
||||
return (RCTLocationOptions){
|
||||
.timeout = [RCTConvert NSTimeInterval:options[@"timeout"]] ?: INFINITY,
|
||||
.maximumAge = [RCTConvert NSTimeInterval:options[@"maximumAge"]] ?: INFINITY,
|
||||
.accuracy = [RCTConvert BOOL:options[@"enableHighAccuracy"]] ? kCLLocationAccuracyBest : RCT_DEFAULT_LOCATION_ACCURACY
|
||||
};
|
||||
}
|
||||
|
||||
static NSDictionary *RCTPositionError(RCTPositionErrorCode code, NSString *msg /* nil for default */)
|
||||
{
|
||||
if (!msg) {
|
||||
switch (code) {
|
||||
case RCTPositionErrorDenied:
|
||||
msg = @"User denied access to location services.";
|
||||
break;
|
||||
case RCTPositionErrorUnavailable:
|
||||
msg = @"Unable to retrieve location.";
|
||||
break;
|
||||
case RCTPositionErrorTimeout:
|
||||
msg = @"The location request timed out.";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return @{
|
||||
@"code": @(code),
|
||||
@"message": msg,
|
||||
@"PERMISSION_DENIED": @(RCTPositionErrorDenied),
|
||||
@"POSITION_UNAVAILABLE": @(RCTPositionErrorUnavailable),
|
||||
@"TIMEOUT": @(RCTPositionErrorTimeout)
|
||||
};
|
||||
}
|
||||
|
||||
@interface RCTLocationRequest : NSObject
|
||||
|
||||
@property (nonatomic, copy) RCTResponseSenderBlock successBlock;
|
||||
@property (nonatomic, copy) RCTResponseSenderBlock errorBlock;
|
||||
@property (nonatomic, assign) RCTLocationOptions options;
|
||||
@property (nonatomic, strong) NSTimer *timeoutTimer;
|
||||
|
||||
@end
|
||||
|
||||
@implementation RCTLocationRequest
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[_timeoutTimer invalidate];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface RCTLocationObserver () <CLLocationManagerDelegate>
|
||||
|
||||
@end
|
||||
|
||||
@implementation RCTLocationObserver
|
||||
{
|
||||
CLLocationManager *_locationManager;
|
||||
NSDictionary *_lastLocationEvent;
|
||||
NSMutableArray *_pendingRequests;
|
||||
BOOL _observingLocation;
|
||||
RCTLocationOptions _observerOptions;
|
||||
}
|
||||
|
||||
@synthesize bridge = _bridge;
|
||||
|
||||
#pragma mark - Lifecycle
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
if ((self = [super init])) {
|
||||
|
||||
_locationManager = [[CLLocationManager alloc] init];
|
||||
_locationManager.distanceFilter = RCT_DEFAULT_LOCATION_ACCURACY;
|
||||
_locationManager.delegate = self;
|
||||
|
||||
_pendingRequests = [[NSMutableArray alloc] init];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[_locationManager stopUpdatingLocation];
|
||||
}
|
||||
|
||||
#pragma mark - Private API
|
||||
|
||||
- (void)beginLocationUpdates
|
||||
{
|
||||
// Request location access permission
|
||||
if ([_locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)]) {
|
||||
[_locationManager requestWhenInUseAuthorization];
|
||||
}
|
||||
|
||||
// Start observing location
|
||||
[_locationManager startUpdatingLocation];
|
||||
}
|
||||
|
||||
#pragma mark - Timeout handler
|
||||
|
||||
- (void)timeout:(NSTimer *)timer
|
||||
{
|
||||
RCTLocationRequest *request = timer.userInfo;
|
||||
NSString *message = [NSString stringWithFormat: @"Unable to fetch location within %zds.", (NSInteger)(timer.timeInterval * 1000.0)];
|
||||
request.errorBlock(@[RCTPositionError(RCTPositionErrorTimeout, message)]);
|
||||
[_pendingRequests removeObject:request];
|
||||
|
||||
// Stop updating if no pending requests
|
||||
if (_pendingRequests.count == 0 && !_observingLocation) {
|
||||
[_locationManager stopUpdatingLocation];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Public API
|
||||
|
||||
- (void)startObserving:(NSDictionary *)optionsJSON
|
||||
{
|
||||
RCT_EXPORT();
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
|
||||
// Select best options
|
||||
_observerOptions = RCTLocationOptionsWithJSON(optionsJSON);
|
||||
for (RCTLocationRequest *request in _pendingRequests) {
|
||||
_observerOptions.accuracy = MIN(_observerOptions.accuracy, request.options.accuracy);
|
||||
}
|
||||
|
||||
_locationManager.desiredAccuracy = _observerOptions.accuracy;
|
||||
[self beginLocationUpdates];
|
||||
_observingLocation = YES;
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
- (void)stopObserving
|
||||
{
|
||||
RCT_EXPORT();
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
|
||||
// Stop observing
|
||||
_observingLocation = NO;
|
||||
|
||||
// Stop updating if no pending requests
|
||||
if (_pendingRequests.count == 0) {
|
||||
[_locationManager stopUpdatingLocation];
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
- (void)getCurrentPosition:(RCTResponseSenderBlock)successBlock
|
||||
withErrorCallback:(RCTResponseSenderBlock)errorBlock
|
||||
options:(NSDictionary *)optionsJSON
|
||||
{
|
||||
RCT_EXPORT();
|
||||
|
||||
if (!successBlock) {
|
||||
RCTLogError(@"%@.getCurrentPosition called with nil success parameter.", [self class]);
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
|
||||
if (![CLLocationManager locationServicesEnabled]) {
|
||||
if (errorBlock) {
|
||||
errorBlock(@[
|
||||
RCTPositionError(RCTPositionErrorUnavailable, @"Location services disabled.")
|
||||
]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (![CLLocationManager authorizationStatus] == kCLAuthorizationStatusDenied) {
|
||||
if (errorBlock) {
|
||||
errorBlock(@[
|
||||
RCTPositionError(RCTPositionErrorDenied, nil)
|
||||
]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Get options
|
||||
RCTLocationOptions options = RCTLocationOptionsWithJSON(optionsJSON);
|
||||
|
||||
// Check if previous recorded location exists and is good enough
|
||||
if (_lastLocationEvent &&
|
||||
CFAbsoluteTimeGetCurrent() - [RCTConvert NSTimeInterval:_lastLocationEvent[@"timestamp"]] < options.maximumAge &&
|
||||
[_lastLocationEvent[@"coords"][@"accuracy"] doubleValue] >= options.accuracy) {
|
||||
|
||||
// Call success block with most recent known location
|
||||
successBlock(@[_lastLocationEvent]);
|
||||
return;
|
||||
}
|
||||
|
||||
// Create request
|
||||
RCTLocationRequest *request = [[RCTLocationRequest alloc] init];
|
||||
request.successBlock = successBlock;
|
||||
request.errorBlock = errorBlock ?: ^(NSArray *args){};
|
||||
request.options = options;
|
||||
request.timeoutTimer = [NSTimer scheduledTimerWithTimeInterval:options.timeout
|
||||
target:self
|
||||
selector:@selector(timeout:)
|
||||
userInfo:request
|
||||
repeats:NO];
|
||||
[_pendingRequests addObject:request];
|
||||
|
||||
// Configure location manager and begin updating location
|
||||
_locationManager.desiredAccuracy = MIN(_locationManager.desiredAccuracy, options.accuracy);
|
||||
[self beginLocationUpdates];
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
#pragma mark - CLLocationManagerDelegate
|
||||
|
||||
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
|
||||
{
|
||||
// Create event
|
||||
CLLocation *location = [locations lastObject];
|
||||
_lastLocationEvent = @{
|
||||
@"coords": @{
|
||||
@"latitude": @(location.coordinate.latitude),
|
||||
@"longitude": @(location.coordinate.longitude),
|
||||
@"altitude": @(location.altitude),
|
||||
@"accuracy": @(location.horizontalAccuracy),
|
||||
@"altitudeAccuracy": @(location.verticalAccuracy),
|
||||
@"heading": @(location.course),
|
||||
@"speed": @(location.speed),
|
||||
},
|
||||
@"timestamp": @(CFAbsoluteTimeGetCurrent() * 1000.0) // in ms
|
||||
};
|
||||
|
||||
// Send event
|
||||
if (_observingLocation) {
|
||||
[_bridge.eventDispatcher sendDeviceEventWithName:@"geolocationDidChange"
|
||||
body:_lastLocationEvent];
|
||||
}
|
||||
|
||||
// Fire all queued callbacks
|
||||
for (RCTLocationRequest *request in _pendingRequests) {
|
||||
request.successBlock(@[_lastLocationEvent]);
|
||||
}
|
||||
[_pendingRequests removeAllObjects];
|
||||
|
||||
// Stop updating if not not observing
|
||||
if (!_observingLocation) {
|
||||
[_locationManager stopUpdatingLocation];
|
||||
}
|
||||
|
||||
// Reset location accuracy
|
||||
_locationManager.desiredAccuracy = RCT_DEFAULT_LOCATION_ACCURACY;
|
||||
}
|
||||
|
||||
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
|
||||
{
|
||||
// Check error type
|
||||
NSDictionary *jsError = nil;
|
||||
switch (error.code) {
|
||||
case kCLErrorDenied:
|
||||
jsError = RCTPositionError(RCTPositionErrorDenied, nil);
|
||||
break;
|
||||
case kCLErrorNetwork:
|
||||
jsError = RCTPositionError(RCTPositionErrorUnavailable, @"Unable to retrieve location due to a network failure");
|
||||
break;
|
||||
case kCLErrorLocationUnknown:
|
||||
default:
|
||||
jsError = RCTPositionError(RCTPositionErrorUnavailable, nil);
|
||||
break;
|
||||
}
|
||||
|
||||
// Send event
|
||||
if (_observingLocation) {
|
||||
[_bridge.eventDispatcher sendDeviceEventWithName:@"geolocationError"
|
||||
body:jsError];
|
||||
}
|
||||
|
||||
// Fire all queued error callbacks
|
||||
for (RCTLocationRequest *request in _pendingRequests) {
|
||||
request.errorBlock(@[jsError]);
|
||||
}
|
||||
[_pendingRequests removeAllObjects];
|
||||
|
||||
// Reset location accuracy
|
||||
_locationManager.desiredAccuracy = RCT_DEFAULT_LOCATION_ACCURACY;
|
||||
}
|
||||
|
||||
@end
|
|
@ -10,7 +10,6 @@ var NativeMethodsMixin = require('NativeMethodsMixin');
|
|||
var NativeModulesDeprecated = require('NativeModulesDeprecated');
|
||||
var PropTypes = require('ReactPropTypes');
|
||||
var ImageResizeMode = require('ImageResizeMode');
|
||||
var ImageSourcePropType = require('ImageSourcePropType');
|
||||
var ImageStylePropTypes = require('ImageStylePropTypes');
|
||||
var React = require('React');
|
||||
var ReactIOSViewAttributes = require('ReactIOSViewAttributes');
|
||||
|
@ -25,31 +24,40 @@ var merge = require('merge');
|
|||
var warning = require('warning');
|
||||
|
||||
/**
|
||||
* <Image> - A react component for displaying different types of images,
|
||||
* A react component for displaying different types of images,
|
||||
* including network images, static resources, temporary local images, and
|
||||
* images from local disk, such as the camera roll. Example usage:
|
||||
* images from local disk, such as the camera roll.
|
||||
*
|
||||
* renderImages: function() {
|
||||
* return (
|
||||
* <View>
|
||||
* <Image
|
||||
* style={styles.icon}
|
||||
* source={ix('myIcon')}
|
||||
* />
|
||||
* <Image
|
||||
* style={styles.logo}
|
||||
* source={{uri: 'http://facebook.github.io/react/img/logo_og.png'}}
|
||||
* />
|
||||
* </View>
|
||||
* );
|
||||
* },
|
||||
* Example usage:
|
||||
*
|
||||
* More example code in ImageExample.js
|
||||
* ```
|
||||
* renderImages: function() {
|
||||
* return (
|
||||
* <View>
|
||||
* <Image
|
||||
* style={styles.icon}
|
||||
* source={ix('myIcon')}
|
||||
* />
|
||||
* <Image
|
||||
* style={styles.logo}
|
||||
* source={{uri: 'http://facebook.github.io/react/img/logo_og.png'}}
|
||||
* />
|
||||
* </View>
|
||||
* );
|
||||
* },
|
||||
* ```
|
||||
*/
|
||||
|
||||
var Image = React.createClass({
|
||||
propTypes: {
|
||||
source: ImageSourcePropType,
|
||||
source: PropTypes.shape({
|
||||
/**
|
||||
* A string representing the resource identifier for the image, which
|
||||
* could be an http address, a local file path, or the name of a static image
|
||||
* resource (which should be wrapped in the `ix` function).
|
||||
*/
|
||||
uri: PropTypes.string,
|
||||
}).isRequired,
|
||||
/**
|
||||
* accessible - Whether this element should be revealed as an accessible
|
||||
* element.
|
||||
|
@ -78,7 +86,6 @@ var Image = React.createClass({
|
|||
|
||||
statics: {
|
||||
resizeMode: ImageResizeMode,
|
||||
sourcePropType: ImageSourcePropType,
|
||||
},
|
||||
|
||||
mixins: [NativeMethodsMixin],
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
/**
|
||||
* Copyright 2004-present Facebook. All Rights Reserved.
|
||||
*
|
||||
* @providesModule ImageSourcePropType
|
||||
* @flow
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var { PropTypes } = require('React');
|
||||
|
||||
var ImageSourcePropType = PropTypes.shape({
|
||||
/**
|
||||
* uri - A string representing the resource identifier for the image, which
|
||||
* could be an http address, a local file path, or the name of a static image
|
||||
* resource (which should be wrapped in the `ix` function).
|
||||
*/
|
||||
uri: PropTypes.string.isRequired,
|
||||
/**
|
||||
* width/height - Used to store the size of the image itself, but unused by
|
||||
* the <Image> component - use normal style layout properties to define the
|
||||
* size of the frame.
|
||||
*/
|
||||
width: PropTypes.number,
|
||||
height: PropTypes.number,
|
||||
});
|
||||
|
||||
module.exports = ImageSourcePropType;
|
|
@ -140,7 +140,7 @@ function setupXHR() {
|
|||
|
||||
function setupGeolocation() {
|
||||
GLOBAL.navigator = GLOBAL.navigator || {};
|
||||
GLOBAL.navigator.geolocation = require('GeoLocation');
|
||||
GLOBAL.navigator.geolocation = require('Geolocation');
|
||||
}
|
||||
|
||||
setupDocumentShim();
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
/**
|
||||
* Copyright 2004-present Facebook. All Rights Reserved.
|
||||
*
|
||||
* @providesModule nativePropType
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
/**
|
||||
* A simple wrapper for prop types to mark them as native, which will allow them
|
||||
* to be passed over the bridge to be applied to the native component if
|
||||
* processed by `validAttributesFromPropTypes`.
|
||||
*/
|
||||
function nativePropType(propType) {
|
||||
propType.isNative = true;
|
||||
return propType;
|
||||
}
|
||||
|
||||
module.exports = nativePropType;
|
|
@ -1,18 +0,0 @@
|
|||
/**
|
||||
* Copyright 2004-present Facebook. All Rights Reserved.
|
||||
*
|
||||
* @providesModule ArrayOfPropType
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
var ReactPropTypes = require('ReactPropTypes');
|
||||
|
||||
var deepDiffer = require('deepDiffer');
|
||||
|
||||
var ArrayOfPropType = (type, differ) => {
|
||||
var checker = ReactPropTypes.arrayOf(type);
|
||||
checker.differ = differ ? differ : deepDiffer;
|
||||
return checker;
|
||||
};
|
||||
|
||||
module.exports = ArrayOfPropType;
|
|
@ -17,6 +17,4 @@ var EdgeInsetsPropType = createStrictShapeTypeChecker({
|
|||
right: PropTypes.number,
|
||||
});
|
||||
|
||||
EdgeInsetsPropType.differ = insetsDiffer;
|
||||
|
||||
module.exports = EdgeInsetsPropType;
|
||||
|
|
|
@ -15,6 +15,4 @@ var PointPropType = createStrictShapeTypeChecker({
|
|||
y: PropTypes.number,
|
||||
});
|
||||
|
||||
PointPropType.differ = pointsDiffer;
|
||||
|
||||
module.exports = PointPropType;
|
||||
|
|
|
@ -28,46 +28,42 @@ var viewConfig = {
|
|||
};
|
||||
|
||||
/**
|
||||
* <Text> - A react component for displaying text which supports nesting,
|
||||
* A react component for displaying text which supports nesting,
|
||||
* styling, and touch handling. In the following example, the nested title and
|
||||
* body text will inherit the `fontFamily` from `styles.baseText`, but the title
|
||||
* provides its own additional styles. The title and body will stack on top of
|
||||
* each other on account of the literal newlines:
|
||||
*
|
||||
* renderText: function() {
|
||||
* return (
|
||||
* <Text style={styles.baseText}>
|
||||
* <Text style={styles.titleText} onPress={this._onPressTitle}>
|
||||
* {this.state.titleText + '\n\n'}
|
||||
* </Text>
|
||||
* <Text numberOfLines={5}>
|
||||
* {this.state.bodyText}
|
||||
* </Text>
|
||||
* ```
|
||||
* renderText: function() {
|
||||
* return (
|
||||
* <Text style={styles.baseText}>
|
||||
* <Text style={styles.titleText} onPress={this.onPressTitle}>
|
||||
* {this.state.titleText + '\n\n'}
|
||||
* </Text>
|
||||
* );
|
||||
* <Text numberOfLines={5}>
|
||||
* {this.state.bodyText}
|
||||
* </Text>
|
||||
* </Text>
|
||||
* );
|
||||
* },
|
||||
* ...
|
||||
* var styles = StyleSheet.create({
|
||||
* baseText: {
|
||||
* fontFamily: 'Cochin',
|
||||
* },
|
||||
* ...
|
||||
* var styles = StyleSheet.create({
|
||||
* baseText: {
|
||||
* fontFamily: 'Cochin',
|
||||
* },
|
||||
* titleText: {
|
||||
* fontSize: 20,
|
||||
* fontWeight: 'bold',
|
||||
* },
|
||||
* };
|
||||
*
|
||||
* More example code in `TextExample.ios.js`
|
||||
* titleText: {
|
||||
* fontSize: 20,
|
||||
* fontWeight: 'bold',
|
||||
* },
|
||||
* };
|
||||
* ```
|
||||
*/
|
||||
|
||||
var Text = React.createClass({
|
||||
|
||||
mixins: [Touchable.Mixin, NativeMethodsMixin],
|
||||
|
||||
statics: {
|
||||
stylePropType: stylePropType,
|
||||
},
|
||||
|
||||
propTypes: {
|
||||
/**
|
||||
* Used to truncate the text with an elipsis after computing the text
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
/**
|
||||
* Copyright 2004-present Facebook. All Rights Reserved.
|
||||
*
|
||||
* @providesModule validAttributesFromPropTypes
|
||||
*/
|
||||
'use strict'
|
||||
|
||||
function validAttributesFromPropTypes(propTypes) {
|
||||
var validAttributes = {};
|
||||
for (var key in propTypes) {
|
||||
var propType = propTypes[key];
|
||||
if (propType && propType.isNative) {
|
||||
var diff = propType.differ;
|
||||
validAttributes[key] = diff ? {diff} : true;
|
||||
}
|
||||
}
|
||||
return validAttributes;
|
||||
}
|
||||
|
||||
module.exports = validAttributesFromPropTypes;
|
|
@ -8,6 +8,7 @@
|
|||
var ReactNative = {
|
||||
...require('React'),
|
||||
AppRegistry: require('AppRegistry'),
|
||||
DatePickerIOS: require('DatePickerIOS'),
|
||||
ExpandingText: require('ExpandingText'),
|
||||
Image: require('Image'),
|
||||
LayoutAnimation: require('LayoutAnimation'),
|
||||
|
@ -17,8 +18,10 @@ var ReactNative = {
|
|||
PixelRatio: require('PixelRatio'),
|
||||
ScrollView: require('ScrollView'),
|
||||
ActivityIndicatorIOS: require('ActivityIndicatorIOS'),
|
||||
Slider: require('Slider'),
|
||||
StatusBarIOS: require('StatusBarIOS'),
|
||||
StyleSheet: require('StyleSheet'),
|
||||
SwitchIOS: require('SwitchIOS'),
|
||||
Text: require('Text'),
|
||||
TextInput: require('TextInput'),
|
||||
TimerMixin: require('TimerMixin'),
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
+ (float)float:(id)json;
|
||||
+ (int)int:(id)json;
|
||||
|
||||
+ (NSArray *)NSArray:(id)json;
|
||||
+ (NSDictionary *)NSDictionary:(id)json;
|
||||
+ (NSString *)NSString:(id)json;
|
||||
+ (NSNumber *)NSNumber:(id)json;
|
||||
+ (NSInteger)NSInteger:(id)json;
|
||||
|
|
|
@ -99,6 +99,8 @@ RCT_CONVERTER(double, double, doubleValue)
|
|||
RCT_CONVERTER(float, float, floatValue)
|
||||
RCT_CONVERTER(int, int, intValue)
|
||||
|
||||
RCT_CONVERTER_CUSTOM(NSArray *, NSArray, [NSArray arrayWithArray:json])
|
||||
RCT_CONVERTER_CUSTOM(NSDictionary *, NSDictionary, [NSDictionary dictionaryWithDictionary:json])
|
||||
RCT_CONVERTER(NSString *, NSString, description)
|
||||
RCT_CONVERTER_CUSTOM(NSNumber *, NSNumber, @([json doubleValue]))
|
||||
RCT_CONVERTER(NSInteger, NSInteger, integerValue)
|
||||
|
|
|
@ -1,182 +0,0 @@
|
|||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#import "RCTLocationObserver.h"
|
||||
|
||||
#import <CoreLocation/CLLocationManager.h>
|
||||
#import <CoreLocation/CLLocationManagerDelegate.h>
|
||||
|
||||
#import "RCTAssert.h"
|
||||
#import "RCTBridge.h"
|
||||
#import "RCTEventDispatcher.h"
|
||||
#import "RCTLog.h"
|
||||
|
||||
// TODO (#5906496): Shouldn't these be configurable?
|
||||
const CLLocationAccuracy RCTLocationAccuracy = 500.0; // meters
|
||||
|
||||
@interface RCTPendingLocationRequest : NSObject
|
||||
|
||||
@property (nonatomic, copy) RCTResponseSenderBlock successBlock;
|
||||
@property (nonatomic, copy) RCTResponseSenderBlock errorBlock;
|
||||
|
||||
@end
|
||||
|
||||
@implementation RCTPendingLocationRequest @end
|
||||
|
||||
@interface RCTLocationObserver () <CLLocationManagerDelegate>
|
||||
|
||||
@end
|
||||
|
||||
@implementation RCTLocationObserver
|
||||
{
|
||||
CLLocationManager *_locationManager;
|
||||
NSDictionary *_lastLocationEvent;
|
||||
NSMutableDictionary *_pendingRequests;
|
||||
}
|
||||
|
||||
@synthesize bridge = _bridge;
|
||||
|
||||
#pragma mark - Lifecycle
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
if ((self = [super init])) {
|
||||
_pendingRequests = [[NSMutableDictionary alloc] init];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[_locationManager stopUpdatingLocation];
|
||||
}
|
||||
|
||||
#pragma mark - Public API
|
||||
|
||||
- (void)startObserving
|
||||
{
|
||||
RCT_EXPORT();
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
|
||||
// Create the location manager if this object does not
|
||||
// already have one, and it must be created and accessed
|
||||
// on the main thread
|
||||
if (nil == _locationManager) {
|
||||
_locationManager = [[CLLocationManager alloc] init];
|
||||
}
|
||||
|
||||
_locationManager.delegate = self;
|
||||
_locationManager.desiredAccuracy = RCTLocationAccuracy;
|
||||
|
||||
// Set a movement threshold for new events.
|
||||
_locationManager.distanceFilter = RCTLocationAccuracy; // meters
|
||||
|
||||
if([_locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)]) {
|
||||
[_locationManager requestWhenInUseAuthorization];
|
||||
}
|
||||
|
||||
[_locationManager startUpdatingLocation];
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
- (void)stopObserving
|
||||
{
|
||||
RCT_EXPORT();
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[_locationManager stopUpdatingLocation];
|
||||
_lastLocationEvent = nil;
|
||||
});
|
||||
}
|
||||
|
||||
#pragma mark - CLLocationManagerDelegate
|
||||
|
||||
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
|
||||
{
|
||||
CLLocation *loc = [locations lastObject];
|
||||
NSDictionary *event = @{
|
||||
@"coords": @{
|
||||
@"latitude": @(loc.coordinate.latitude),
|
||||
@"longitude": @(loc.coordinate.longitude),
|
||||
@"altitude": @(loc.altitude),
|
||||
@"accuracy": @(RCTLocationAccuracy),
|
||||
@"altitudeAccuracy": @(RCTLocationAccuracy),
|
||||
@"heading": @(loc.course),
|
||||
@"speed": @(loc.speed),
|
||||
},
|
||||
@"timestamp": @(CACurrentMediaTime())
|
||||
};
|
||||
[_bridge.eventDispatcher sendDeviceEventWithName:@"geoLocationDidChange" body:event];
|
||||
NSArray *pendingRequestsCopy;
|
||||
|
||||
// TODO (#5906496): is this locking neccessary? If so, use something better than @synchronize
|
||||
@synchronized(self) {
|
||||
|
||||
pendingRequestsCopy = [_pendingRequests allValues];
|
||||
[_pendingRequests removeAllObjects];
|
||||
|
||||
_lastLocationEvent = event;
|
||||
}
|
||||
|
||||
for (RCTPendingLocationRequest *request in pendingRequestsCopy) {
|
||||
if (request.successBlock) {
|
||||
request.successBlock(@[event]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
|
||||
{
|
||||
NSArray *pendingRequestsCopy;
|
||||
|
||||
// TODO (#5906496): is this locking neccessary? If so, use something better than @synchronize
|
||||
@synchronized(self) {
|
||||
pendingRequestsCopy = [_pendingRequests allValues];
|
||||
[_pendingRequests removeAllObjects];
|
||||
}
|
||||
|
||||
NSString *errorMsg = @"User denied location service or location service not available.";
|
||||
for (RCTPendingLocationRequest *request in pendingRequestsCopy) {
|
||||
if (request.errorBlock) {
|
||||
request.errorBlock(@[errorMsg]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)getCurrentPosition:(RCTResponseSenderBlock)geoSuccess withErrorCallback:(RCTResponseSenderBlock)geoError
|
||||
{
|
||||
RCT_EXPORT();
|
||||
|
||||
NSDictionary *lastLocationCopy;
|
||||
// TODO (#5906496): is this locking neccessary? If so, use something better than @synchronize
|
||||
@synchronized(self) {
|
||||
if (![CLLocationManager locationServicesEnabled] || [CLLocationManager authorizationStatus] == kCLAuthorizationStatusDenied) {
|
||||
if (geoError) {
|
||||
NSString *errorMsg = @"User denied location service or location service not available.";
|
||||
geoError(@[errorMsg]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// If a request for the current position comes in before the OS has informed us, we wait for the first
|
||||
// OS event and then call our callbacks. This obviates the need for handling of the otherwise
|
||||
// common failure case of requesting the geolocation until it succeeds, assuming we would have
|
||||
// instead returned an error if it wasn't yet available.
|
||||
if (!_lastLocationEvent) {
|
||||
NSInteger requestID = [_pendingRequests count];
|
||||
RCTPendingLocationRequest *request = [[RCTPendingLocationRequest alloc] init];
|
||||
request.successBlock = geoSuccess;
|
||||
request.errorBlock = geoError;
|
||||
_pendingRequests[@(requestID)] = request;
|
||||
return;
|
||||
} else {
|
||||
lastLocationCopy = [_lastLocationEvent copy];
|
||||
}
|
||||
}
|
||||
if (geoSuccess) {
|
||||
geoSuccess(@[lastLocationCopy]);
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
|
@ -74,8 +74,9 @@ UIViewAnimationCurve UIViewAnimationCurveFromRCTAnimationType(RCTAnimationType t
|
|||
_property = [RCTConvert NSString:config[@"property"]];
|
||||
|
||||
// TODO: this should be provided in ms, not seconds
|
||||
_duration = [RCTConvert NSTimeInterval:config[@"duration"]] ?: duration;
|
||||
_delay = [RCTConvert NSTimeInterval:config[@"delay"]];
|
||||
// (this will require changing all call sites to ms as well)
|
||||
_duration = [RCTConvert NSTimeInterval:config[@"duration"]] * 1000.0 ?: duration;
|
||||
_delay = [RCTConvert NSTimeInterval:config[@"delay"]] * 1000.0;
|
||||
_animationType = [RCTConvert RCTAnimationType:config[@"type"]];
|
||||
if (_animationType == RCTAnimationTypeSpring) {
|
||||
_springDamping = [RCTConvert CGFloat:config[@"springDamping"]];
|
||||
|
@ -135,7 +136,8 @@ UIViewAnimationCurve UIViewAnimationCurveFromRCTAnimationType(RCTAnimationType t
|
|||
if ((self = [super init])) {
|
||||
|
||||
// TODO: this should be provided in ms, not seconds
|
||||
NSTimeInterval duration = [RCTConvert NSTimeInterval:config[@"duration"]];
|
||||
// (this will require changing all call sites to ms as well)
|
||||
NSTimeInterval duration = [RCTConvert NSTimeInterval:config[@"duration"]] * 1000.0;
|
||||
|
||||
_createAnimation = [[RCTAnimation alloc] initWithDuration:duration dictionary:config[@"create"]];
|
||||
_updateAnimation = [[RCTAnimation alloc] initWithDuration:duration dictionary:config[@"update"]];
|
||||
|
|
|
@ -34,7 +34,10 @@
|
|||
13E067561A70F44B002CDEE1 /* RCTViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E0674E1A70F44B002CDEE1 /* RCTViewManager.m */; };
|
||||
13E067571A70F44B002CDEE1 /* RCTView.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E067501A70F44B002CDEE1 /* RCTView.m */; };
|
||||
13E067591A70F44B002CDEE1 /* UIView+ReactKit.m in Sources */ = {isa = PBXBuildFile; fileRef = 13E067541A70F44B002CDEE1 /* UIView+ReactKit.m */; };
|
||||
5F5F0D991A9E456B001279FA /* RCTLocationObserver.m in Sources */ = {isa = PBXBuildFile; fileRef = 5F5F0D981A9E456B001279FA /* RCTLocationObserver.m */; };
|
||||
58C571C11AA56C1900CDF9C8 /* RCTDatePickerManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 58C571BF1AA56C1900CDF9C8 /* RCTDatePickerManager.m */; };
|
||||
14F3620D1AABD06A001CE568 /* RCTSwitch.m in Sources */ = {isa = PBXBuildFile; fileRef = 14F362081AABD06A001CE568 /* RCTSwitch.m */; };
|
||||
14F3620E1AABD06A001CE568 /* RCTSwitchManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 14F3620A1AABD06A001CE568 /* RCTSwitchManager.m */; };
|
||||
14F484561AABFCE100FDF6B9 /* RCTSliderManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 14F484551AABFCE100FDF6B9 /* RCTSliderManager.m */; };
|
||||
830A229E1A66C68A008503DA /* RCTRootView.m in Sources */ = {isa = PBXBuildFile; fileRef = 830A229D1A66C68A008503DA /* RCTRootView.m */; };
|
||||
830BA4551A8E3BDA00D53203 /* RCTCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 830BA4541A8E3BDA00D53203 /* RCTCache.m */; };
|
||||
832348161A77A5AA00B55238 /* Layout.c in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FC71A68125100A75B9A /* Layout.c */; };
|
||||
|
@ -123,8 +126,14 @@
|
|||
13E067531A70F44B002CDEE1 /* UIView+ReactKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+ReactKit.h"; sourceTree = "<group>"; };
|
||||
13E067541A70F44B002CDEE1 /* UIView+ReactKit.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+ReactKit.m"; sourceTree = "<group>"; };
|
||||
13EFFCCF1A98E6FE002607DC /* RCTJSMethodRegistrar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTJSMethodRegistrar.h; sourceTree = "<group>"; };
|
||||
5F5F0D971A9E456B001279FA /* RCTLocationObserver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTLocationObserver.h; sourceTree = "<group>"; };
|
||||
5F5F0D981A9E456B001279FA /* RCTLocationObserver.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTLocationObserver.m; sourceTree = "<group>"; };
|
||||
58C571BF1AA56C1900CDF9C8 /* RCTDatePickerManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTDatePickerManager.m; sourceTree = "<group>"; };
|
||||
58C571C01AA56C1900CDF9C8 /* RCTDatePickerManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTDatePickerManager.h; sourceTree = "<group>"; };
|
||||
14F362071AABD06A001CE568 /* RCTSwitch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTSwitch.h; sourceTree = "<group>"; };
|
||||
14F362081AABD06A001CE568 /* RCTSwitch.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTSwitch.m; sourceTree = "<group>"; };
|
||||
14F362091AABD06A001CE568 /* RCTSwitchManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTSwitchManager.h; sourceTree = "<group>"; };
|
||||
14F3620A1AABD06A001CE568 /* RCTSwitchManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTSwitchManager.m; sourceTree = "<group>"; };
|
||||
14F484541AABFCE100FDF6B9 /* RCTSliderManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTSliderManager.h; sourceTree = "<group>"; };
|
||||
14F484551AABFCE100FDF6B9 /* RCTSliderManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTSliderManager.m; sourceTree = "<group>"; };
|
||||
830213F31A654E0800B993E6 /* RCTBridgeModule.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RCTBridgeModule.h; sourceTree = "<group>"; };
|
||||
830A229C1A66C68A008503DA /* RCTRootView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTRootView.h; sourceTree = "<group>"; };
|
||||
830A229D1A66C68A008503DA /* RCTRootView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTRootView.m; sourceTree = "<group>"; };
|
||||
|
@ -187,8 +196,6 @@
|
|||
13B07FE01A69315300A75B9A /* Modules */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5F5F0D971A9E456B001279FA /* RCTLocationObserver.h */,
|
||||
5F5F0D981A9E456B001279FA /* RCTLocationObserver.m */,
|
||||
13B07FE71A69327A00A75B9A /* RCTAlertManager.h */,
|
||||
13B07FE81A69327A00A75B9A /* RCTAlertManager.m */,
|
||||
13B07FE91A69327A00A75B9A /* RCTExceptionsManager.h */,
|
||||
|
@ -206,7 +213,15 @@
|
|||
13B07FF31A6947C200A75B9A /* Views */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
14F362071AABD06A001CE568 /* RCTSwitch.h */,
|
||||
14F362081AABD06A001CE568 /* RCTSwitch.m */,
|
||||
14F362091AABD06A001CE568 /* RCTSwitchManager.h */,
|
||||
14F3620A1AABD06A001CE568 /* RCTSwitchManager.m */,
|
||||
14F484541AABFCE100FDF6B9 /* RCTSliderManager.h */,
|
||||
14F484551AABFCE100FDF6B9 /* RCTSliderManager.m */,
|
||||
13442BF21AA90E0B0037E5B0 /* RCTAnimationType.h */,
|
||||
58C571C01AA56C1900CDF9C8 /* RCTDatePickerManager.h */,
|
||||
58C571BF1AA56C1900CDF9C8 /* RCTDatePickerManager.m */,
|
||||
13442BF31AA90E0B0037E5B0 /* RCTPointerEvents.h */,
|
||||
13442BF41AA90E0B0037E5B0 /* RCTViewControllerProtocol.h */,
|
||||
13C325261AA63B6A0048765F /* RCTAutoInsetsProtocol.h */,
|
||||
|
@ -393,14 +408,16 @@
|
|||
13B0801E1A69489C00A75B9A /* RCTTextField.m in Sources */,
|
||||
13B07FEF1A69327A00A75B9A /* RCTAlertManager.m in Sources */,
|
||||
83CBBACC1A6023D300E9B192 /* RCTConvert.m in Sources */,
|
||||
5F5F0D991A9E456B001279FA /* RCTLocationObserver.m in Sources */,
|
||||
830A229E1A66C68A008503DA /* RCTRootView.m in Sources */,
|
||||
13B07FF01A69327A00A75B9A /* RCTExceptionsManager.m in Sources */,
|
||||
83CBBA5A1A601E9000E9B192 /* RCTRedBox.m in Sources */,
|
||||
83CBBA511A601E3B00E9B192 /* RCTAssert.m in Sources */,
|
||||
832348161A77A5AA00B55238 /* Layout.c in Sources */,
|
||||
14F3620D1AABD06A001CE568 /* RCTSwitch.m in Sources */,
|
||||
14F3620E1AABD06A001CE568 /* RCTSwitchManager.m in Sources */,
|
||||
13B080201A69489C00A75B9A /* RCTUIActivityIndicatorViewManager.m in Sources */,
|
||||
13E067561A70F44B002CDEE1 /* RCTViewManager.m in Sources */,
|
||||
58C571C11AA56C1900CDF9C8 /* RCTDatePickerManager.m in Sources */,
|
||||
13B080061A6947C200A75B9A /* RCTScrollViewManager.m in Sources */,
|
||||
137327EA1AA5CF210034F82E /* RCTTabBarManager.m in Sources */,
|
||||
13B080261A694A8400A75B9A /* RCTWrapperViewController.m in Sources */,
|
||||
|
@ -409,6 +426,7 @@
|
|||
13B0801F1A69489C00A75B9A /* RCTTextFieldManager.m in Sources */,
|
||||
134FCB3D1A6E7F0800051CC8 /* RCTContextExecutor.m in Sources */,
|
||||
13E067591A70F44B002CDEE1 /* UIView+ReactKit.m in Sources */,
|
||||
14F484561AABFCE100FDF6B9 /* RCTSliderManager.m in Sources */,
|
||||
83CBBA981A6020BB00E9B192 /* RCTTouchHandler.m in Sources */,
|
||||
83CBBA521A601E3B00E9B192 /* RCTLog.m in Sources */,
|
||||
13B0801D1A69489C00A75B9A /* RCTNavItemManager.m in Sources */,
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#import "RCTViewManager.h"
|
||||
|
||||
@interface RCTDatePickerManager : RCTViewManager
|
||||
|
||||
@end
|
|
@ -0,0 +1,51 @@
|
|||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#import "RCTDatePickerManager.h"
|
||||
|
||||
#import "RCTBridge.h"
|
||||
#import "RCTConvert.h"
|
||||
#import "RCTEventDispatcher.h"
|
||||
#import "UIView+ReactKit.h"
|
||||
|
||||
@implementation RCTDatePickerManager
|
||||
|
||||
- (UIView *)view
|
||||
{
|
||||
UIDatePicker *picker = [[UIDatePicker alloc] init];
|
||||
[picker addTarget:self
|
||||
action:@selector(onChange:)
|
||||
forControlEvents:UIControlEventValueChanged];
|
||||
return picker;
|
||||
}
|
||||
|
||||
RCT_EXPORT_VIEW_PROPERTY(date)
|
||||
RCT_EXPORT_VIEW_PROPERTY(minimumDate)
|
||||
RCT_EXPORT_VIEW_PROPERTY(maximumDate)
|
||||
RCT_EXPORT_VIEW_PROPERTY(minuteInterval)
|
||||
RCT_REMAP_VIEW_PROPERTY(mode, datePickerMode)
|
||||
RCT_REMAP_VIEW_PROPERTY(timeZoneOffsetInMinutes, timeZone)
|
||||
|
||||
- (void)onChange:(UIDatePicker *)sender
|
||||
{
|
||||
NSDictionary *event = @{
|
||||
@"target": sender.reactTag,
|
||||
@"timestamp": @([sender.date timeIntervalSince1970] * 1000.0)
|
||||
};
|
||||
[self.bridge.eventDispatcher sendInputEventWithName:@"topChange" body:event];
|
||||
}
|
||||
|
||||
- (NSDictionary *)constantsToExport
|
||||
{
|
||||
UIDatePicker *dp = [[UIDatePicker alloc] init];
|
||||
return @{
|
||||
@"ComponentHeight": @(CGRectGetHeight(dp.frame)),
|
||||
@"ComponentWidth": @(CGRectGetWidth(dp.frame)),
|
||||
@"DatePickerModes": @{
|
||||
@"time": @(UIDatePickerModeTime),
|
||||
@"date": @(UIDatePickerModeDate),
|
||||
@"datetime": @(UIDatePickerModeDateAndTime),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@end
|
|
@ -32,8 +32,8 @@ typedef void (^RCTApplierBlock)(RCTSparseArray *);
|
|||
@property (nonatomic, weak, readonly) RCTShadowView *superview;
|
||||
@property (nonatomic, assign, readonly) css_node_t *cssNode;
|
||||
@property (nonatomic, copy) NSString *moduleName;
|
||||
@property (nonatomic, assign) BOOL isBGColorExplicitlySet; // Used to propogate to children
|
||||
@property (nonatomic, strong) UIColor *backgroundColor; // Used to propogate to children
|
||||
@property (nonatomic, assign) BOOL isBGColorExplicitlySet; // Used to propagate to children
|
||||
@property (nonatomic, strong) UIColor *backgroundColor; // Used to propagate to children
|
||||
@property (nonatomic, assign) RCTUpdateLifecycle layoutLifecycle;
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#import "RCTViewManager.h"
|
||||
|
||||
@interface RCTSliderManager : RCTViewManager
|
||||
|
||||
@end
|
|
@ -0,0 +1,43 @@
|
|||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#import "RCTSliderManager.h"
|
||||
|
||||
#import "RCTBridge.h"
|
||||
#import "RCTEventDispatcher.h"
|
||||
#import "UIView+ReactKit.h"
|
||||
|
||||
@implementation RCTSliderManager
|
||||
|
||||
- (UIView *)view
|
||||
{
|
||||
UISlider *slider = [[UISlider alloc] init];
|
||||
[slider addTarget:self action:@selector(sliderValueChanged:) forControlEvents:UIControlEventValueChanged];
|
||||
[slider addTarget:self action:@selector(sliderTouchEnd:) forControlEvents:UIControlEventTouchUpInside];
|
||||
return slider;
|
||||
}
|
||||
|
||||
- (void)sliderValueChanged:(UISlider *)sender
|
||||
{
|
||||
NSDictionary *event = @{
|
||||
@"target": sender.reactTag,
|
||||
@"value": @(sender.value),
|
||||
@"continuous": @YES,
|
||||
};
|
||||
|
||||
[self.bridge.eventDispatcher sendInputEventWithName:@"topChange" body:event];
|
||||
}
|
||||
|
||||
- (void)sliderTouchEnd:(UISlider *)sender
|
||||
{
|
||||
NSDictionary *event = @{
|
||||
@"target": sender.reactTag,
|
||||
@"value": @(sender.value),
|
||||
@"continuous": @NO,
|
||||
};
|
||||
|
||||
[self.bridge.eventDispatcher sendInputEventWithName:@"topChange" body:event];
|
||||
}
|
||||
|
||||
RCT_EXPORT_VIEW_PROPERTY(value);
|
||||
|
||||
@end
|
|
@ -0,0 +1,10 @@
|
|||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface RCTSwitch : UISwitch
|
||||
|
||||
@property (nonatomic, assign) BOOL wasOn;
|
||||
|
||||
@end
|
|
@ -0,0 +1,15 @@
|
|||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#import "RCTSwitch.h"
|
||||
|
||||
#import "RCTEventDispatcher.h"
|
||||
#import "UIView+ReactKit.h"
|
||||
|
||||
@implementation RCTSwitch
|
||||
|
||||
- (void)setOn:(BOOL)on animated:(BOOL)animated {
|
||||
_wasOn = on;
|
||||
[super setOn:on animated:animated];
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,7 @@
|
|||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#import "RCTViewManager.h"
|
||||
|
||||
@interface RCTSwitchManager : RCTViewManager
|
||||
|
||||
@end
|
|
@ -0,0 +1,39 @@
|
|||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#import "RCTSwitchManager.h"
|
||||
|
||||
#import "RCTBridge.h"
|
||||
#import "RCTEventDispatcher.h"
|
||||
#import "RCTSwitch.h"
|
||||
#import "UIView+ReactKit.h"
|
||||
|
||||
@implementation RCTSwitchManager
|
||||
|
||||
- (UIView *)view
|
||||
{
|
||||
RCTSwitch *switcher = [[RCTSwitch alloc] init];
|
||||
[switcher addTarget:self
|
||||
action:@selector(onChange:)
|
||||
forControlEvents:UIControlEventValueChanged];
|
||||
return switcher;
|
||||
}
|
||||
|
||||
- (void)onChange:(RCTSwitch *)sender
|
||||
{
|
||||
if (sender.wasOn != sender.on) {
|
||||
[self.bridge.eventDispatcher sendInputEventWithName:@"topChange" body:@{
|
||||
@"target": sender.reactTag,
|
||||
@"value": @(sender.on)
|
||||
}];
|
||||
|
||||
sender.wasOn = sender.on;
|
||||
}
|
||||
}
|
||||
|
||||
RCT_EXPORT_VIEW_PROPERTY(onTintColor);
|
||||
RCT_EXPORT_VIEW_PROPERTY(tintColor);
|
||||
RCT_EXPORT_VIEW_PROPERTY(thumbTintColor);
|
||||
RCT_EXPORT_VIEW_PROPERTY(on);
|
||||
RCT_EXPORT_VIEW_PROPERTY(enabled);
|
||||
|
||||
@end
|
|
@ -1,7 +1,6 @@
|
|||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
/**
|
||||
|
||||
* Logical node in a tree of application components. Both `ShadowView`s and
|
||||
* `UIView+ReactKit`s conform to this. Allows us to write utilities that
|
||||
* reason about trees generally.
|
||||
|
|
Загрузка…
Ссылка в новой задаче