Skip to content

Commit

Permalink
feat(ReactPickerView): Add ReactPickerView
Browse files Browse the repository at this point in the history
ReactPicker provides access to native selector UI components for React
Native JavaScript applications.
- PR comments implemented

Fixes #231
  • Loading branch information
ebragge authored and rozele committed May 25, 2016
1 parent 24e518f commit 56903eb
Show file tree
Hide file tree
Showing 6 changed files with 193 additions and 45 deletions.
1 change: 0 additions & 1 deletion ReactNative.Tests/ReactNative.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,6 @@
<Compile Include="UnitTestApp.xaml.cs">
<DependentUpon>UnitTestApp.xaml</DependentUpon>
</Compile>
<Compile Include="Views\Picker\ReactPickerTests.cs" />
<Compile Include="Views\TextInput\ReactTextBoxPropertiesTests.cs" />
</ItemGroup>
<ItemGroup>
Expand Down
20 changes: 0 additions & 20 deletions ReactNative.Tests/Views/Picker/ReactPickerTests.cs

This file was deleted.

40 changes: 16 additions & 24 deletions ReactNative/Views/Picker/ReactPickerManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
using ReactNative.UIManager;
using ReactNative.UIManager.Events;
using System;
using Windows.UI;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;
Expand All @@ -14,12 +13,6 @@ namespace ReactNative.Views.Picker
/// </summary>
public class ReactPickerManager : BaseViewManager<ComboBox, ReactPickerShadowNode>
{
private const string PROP_COLOR = "color";
private const string PROP_ENABLED = "enabled";
private const string PROP_ITEMS = "items";
private const string PROP_LABEL = "label";
private const string PROP_SELECTED = "selected";

private int _selected;

/// <summary>
Expand All @@ -41,7 +34,7 @@ public override string Name
/// Set to <code>true</code> if the picker should be enabled,
/// otherwise, set to <code>false</code>.
/// </param>
[ReactProperty(PROP_ENABLED)]
[ReactProperty("enabled")]
public void SetEnabled(ComboBox view, bool enabled)
{
view.IsEnabled = enabled;
Expand All @@ -52,16 +45,16 @@ public void SetEnabled(ComboBox view, bool enabled)
/// </summary>
/// <param name="view">a combobox instance.</param>
/// <param name="selected">The selected item.</param>
[ReactProperty(PROP_SELECTED)]
[ReactProperty("selected")]
public void SetSelected(ComboBox view, int selected)
{
// Temporarily disable selection changed event handler.
view.SelectionChanged -= OnSelectionChanged;

_selected = selected >= -1 ? selected : -1;
view.SelectedIndex = view.Items.Count > _selected ? _selected : view.Items.Count - 1;
_selected = selected;
view.SelectedIndex = view.Items.Count > _selected ? _selected : -1;

if (view.SelectedIndex != -1 )
if (view.SelectedIndex != -1)
{
view.Foreground = ((ComboBoxItem)(view.Items[view.SelectedIndex])).Foreground;
}
Expand All @@ -74,30 +67,29 @@ public void SetSelected(ComboBox view, int selected)
/// </summary>
/// <param name="view">a combobox instance.</param>
/// <param name="items">The picker items.</param>
[ReactProperty(PROP_ITEMS)]
[ReactProperty("items")]
public void SetItems(ComboBox view, JArray items)
{
// Temporarily disable selection changed event handler.
view.SelectionChanged -= OnSelectionChanged;

for (int index = 0; index < items.Count; index++)
for (var index = 0; index < items.Count; index++)
{
JToken token;
if ( (items[index] as JObject).TryGetValue(PROP_LABEL, out token) )
JToken label;
if ((items[index] as JObject).TryGetValue("label", out label))
{
var item = new ComboBoxItem();
JToken color;
item.Content = token.Value<string>();
if (((JObject)(items[index])).TryGetValue(PROP_COLOR, out color) )
item.Content = label.Value<string>();
if ((color = items[index].Value<JToken>("color")) != null)
{
var rgb = color.Value<long>();
item.Foreground = new SolidColorBrush(Color.FromArgb((byte)((rgb >> 24) & 0xff),
(byte)((rgb >> 16) & 0xff),
(byte)((rgb >> 8) & 0xff),
(byte)(rgb & 0xff)));
var rgb = color.Value<uint>();
item.Foreground = new SolidColorBrush(ColorHelpers.Parse(rgb));
}
view.Items.Add(item);
}
}
}

view.SelectedIndex = view.Items.Count > _selected ? _selected : -1;

view.SelectionChanged += OnSelectionChanged;
Expand Down
20 changes: 20 additions & 0 deletions js/Components/Picker/PickerAndroid.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @providesModule PickerAndroid
*/
'use strict';

var React = require('React');

var PickerAndroid = React.createClass({
render: function() {
},
});

module.exports = PickerAndroid;
20 changes: 20 additions & 0 deletions js/Components/Picker/PickerIOS.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @providesModule PickerIOS
*/
'use strict';

var React = require('React');

var PickerIOS = React.createClass({
render: function() {
},
});

module.exports = PickerIOS;
137 changes: 137 additions & 0 deletions js/Components/Picker/PickerWindows.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @providesModule PickerWindows
* @flow
*/

'use strict';

var ColorPropType = require('ColorPropType');
var React = require('React');
var ReactChildren = require('ReactChildren');
var ReactPropTypes = require('ReactPropTypes');
var StyleSheet = require('StyleSheet');
var StyleSheetPropType = require('StyleSheetPropType');
var View = require('View');
var ViewStylePropTypes = require('ViewStylePropTypes');

var processColor = require('processColor');
var requireNativeComponent = require('requireNativeComponent');

var REF_PICKER = 'picker';

var pickerStyleType = StyleSheetPropType({
...ViewStylePropTypes,
color: ColorPropType,
});

type Event = Object;

/**
* Not exposed as a public API - use <Picker> instead.
*/
var PickerWindows = React.createClass({

propTypes: {
...View.propTypes,
style: pickerStyleType,
items: React.PropTypes.any,
selected: React.PropTypes.number,
selectedValue: React.PropTypes.any,
enabled: ReactPropTypes.bool,
onValueChange: ReactPropTypes.func,
prompt: ReactPropTypes.string,
testID: ReactPropTypes.string,
},

getInitialState: function() {
return this._stateFromProps(this.props);
},

componentWillReceiveProps: function(nextProps) {
this.setState(this._stateFromProps(nextProps));
},

// Translate prop and children into stuff that the native picker understands.
_stateFromProps: function(props) {
var selectedIndex = 0;
let items = ReactChildren.map(props.children, (child, index) => {
if (child.props.value === props.selectedValue) {
selectedIndex = index;
}
let childProps = {
value: child.props.value,
label: child.props.label,
};
if (child.props.color) {
childProps.color = processColor(child.props.color);
}
return childProps;
});
return {selectedIndex, items};
},

render: function() {
var Picker = ComboBoxPicker;

var nativeProps = {
enabled: this.props.enabled,
items: this.state.items,
onSelect: this._onChange,
prompt: this.props.prompt,
selected: this.state.selectedIndex,
testID: this.props.testID,
style: [styles.pickerWindows, this.props.style],
};

return <Picker ref={REF_PICKER} {...nativeProps} />;
},

_onChange: function(event: Object) {
if (this.props.onValueChange) {
var position = event.nativeEvent.position;
if (position >= 0) {
var value = this.props.children[position].props.value;
this.props.onValueChange(value, position);
} else {
this.props.onValueChange(null, position);
}
}

// The picker is a controlled component. This means we expect the
// on*Change handlers to be in charge of updating our
// `selectedValue` 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.
if (this.refs[REF_PICKER] && this.state.selectedIndex !== event.nativeEvent.position) {
this.refs[REF_PICKER].setNativeProps({selected: this.state.selectedIndex});
}
},
});

var styles = StyleSheet.create({
pickerWindows: {
// The picker will conform to whatever width is given, but we do
// have to set the component's height explicitly on the
// surrounding view to ensure it gets rendered.
// TODO would be better to export a native constant for this,
// like in iOS the RCTDatePickerManager.m
height: 40,
},
});

var cfg = {
nativeOnly: {
}
};

var ComboBoxPicker = requireNativeComponent('RCTPicker', PickerWindows, PickerWindows, cfg);

module.exports = PickerWindows;

0 comments on commit 56903eb

Please sign in to comment.