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:
Christopher Chedeau 2015-03-09 16:18:15 -07:00
parent 05ec075c94
commit cb9b1f7b29
50 changed files with 1998 additions and 653 deletions

View File

@ -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,
},
});

View File

@ -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',

View File

@ -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 />; }
}
];

View File

@ -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 />; }
}
];

View File

@ -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 */

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:UIExplorer.xcodeproj">
</FileRef>
</Workspace>

View File

@ -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({

View File

@ -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({

View File

@ -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;

View File

@ -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],

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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() {

View File

@ -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,
},
/**

View File

@ -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],

View File

@ -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({

View File

@ -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;

View File

@ -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;

View File

@ -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 */;
}

View File

@ -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

View File

@ -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],

View File

@ -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;

View File

@ -140,7 +140,7 @@ function setupXHR() {
function setupGeolocation() {
GLOBAL.navigator = GLOBAL.navigator || {};
GLOBAL.navigator.geolocation = require('GeoLocation');
GLOBAL.navigator.geolocation = require('Geolocation');
}
setupDocumentShim();

View File

@ -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;

View File

@ -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;

View File

@ -17,6 +17,4 @@ var EdgeInsetsPropType = createStrictShapeTypeChecker({
right: PropTypes.number,
});
EdgeInsetsPropType.differ = insetsDiffer;
module.exports = EdgeInsetsPropType;

View File

@ -15,6 +15,4 @@ var PointPropType = createStrictShapeTypeChecker({
y: PropTypes.number,
});
PointPropType.differ = pointsDiffer;
module.exports = PointPropType;

View File

@ -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

View File

@ -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;

View File

@ -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'),

View File

@ -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;

View File

@ -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)

View File

@ -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

View File

@ -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"]];

View File

@ -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 */,

View File

@ -0,0 +1,7 @@
// Copyright 2004-present Facebook. All Rights Reserved.
#import "RCTViewManager.h"
@interface RCTDatePickerManager : RCTViewManager
@end

View File

@ -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

View File

@ -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;
/**

View File

@ -0,0 +1,7 @@
// Copyright 2004-present Facebook. All Rights Reserved.
#import "RCTViewManager.h"
@interface RCTSliderManager : RCTViewManager
@end

View File

@ -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

View File

@ -0,0 +1,10 @@
// Copyright 2004-present Facebook. All Rights Reserved.
#import <UIKit/UIKit.h>
@interface RCTSwitch : UISwitch
@property (nonatomic, assign) BOOL wasOn;
@end

View File

@ -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

View File

@ -0,0 +1,7 @@
// Copyright 2004-present Facebook. All Rights Reserved.
#import "RCTViewManager.h"
@interface RCTSwitchManager : RCTViewManager
@end

View File

@ -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

View File

@ -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.