Skip to content

Commit

Permalink
Merge pull request #265 from CatalystCode/issue231
Browse files Browse the repository at this point in the history
feat(ReactPickerView): Add ReactPickerView
  • Loading branch information
ebragge committed Mar 21, 2016
2 parents 1890e1a + d39f676 commit 02b9ded
Show file tree
Hide file tree
Showing 8 changed files with 385 additions and 0 deletions.
3 changes: 3 additions & 0 deletions Libraries/Components/Picker/Picker.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
var ColorPropType = require('ColorPropType');
var PickerIOS = require('PickerIOS');
var PickerAndroid = require('PickerAndroid');
var PickerWindows = require('PickerWindows');
var Platform = require('Platform');
var React = require('React');
var StyleSheet = require('StyleSheet');
Expand Down Expand Up @@ -112,6 +113,8 @@ var Picker = React.createClass({
return <PickerIOS {...this.props}>{this.props.children}</PickerIOS>;
} else if (Platform.OS === 'android') {
return <PickerAndroid {...this.props}>{this.props.children}</PickerAndroid>;
} else if (Platform.OS === 'windows') {
return <PickerWindows {...this.props}>{this.props.children}</PickerWindows>;
} else {
return <UnimplementedView />;
}
Expand Down
2 changes: 2 additions & 0 deletions ReactWindows/ReactNative/ReactNative.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,8 @@
<Compile Include="Views\Image\ReactImageLoadEvent.cs" />
<Compile Include="Views\Image\ReactImageManager.cs" />
<Compile Include="Views\Image\ReactVirtualImageManager.cs" />
<Compile Include="Views\Picker\ReactPickerManager.cs" />
<Compile Include="Views\Picker\ReactPickerShadowNode.cs" />
<Compile Include="Views\Scroll\IScrollCommandHandler.cs" />
<Compile Include="Views\Scroll\ReactScrollViewCommandHelper.cs" />
<Compile Include="Views\Scroll\ScrollEventType.cs" />
Expand Down
2 changes: 2 additions & 0 deletions ReactWindows/ReactNative/Shell/MainReactPackage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using ReactNative.Modules.WebSocket;
using ReactNative.UIManager;
using ReactNative.Views.Image;
using ReactNative.Views.Picker;
using ReactNative.Views.Scroll;
using ReactNative.Views.Switch;
using ReactNative.Views.Text;
Expand Down Expand Up @@ -73,6 +74,7 @@ public IReadOnlyList<IViewManager> CreateViewManagers(
new ReactImageManager(),
new ReactVirtualImageManager(),
//new ReactProgressBarViewManager(),
new ReactPickerManager(),
new ReactRawTextManager(),
//new RecyclerViewBackedScrollViewManager(),
new ReactScrollViewManager(),
Expand Down
199 changes: 199 additions & 0 deletions ReactWindows/ReactNative/Views/Picker/ReactPickerManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
using Newtonsoft.Json.Linq;
using ReactNative.UIManager;
using ReactNative.UIManager.Events;
using System;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;

namespace ReactNative.Views.Picker
{
/// <summary>
/// A view manager responsible for rendering picker.
/// </summary>
public class ReactPickerManager : BaseViewManager<ComboBox, ReactPickerShadowNode>
{
/// <summary>
/// The name of the view manager.
/// </summary>
public override string Name
{
get
{
return "RCTPicker";
}
}

/// <summary>
/// Sets whether a picker is enabled.
/// </summary>
/// <param name="view">a combobox view.</param>
/// <param name="enabled">
/// Set to <code>true</code> if the picker should be enabled,
/// otherwise, set to <code>false</code>.
/// </param>
[ReactProperty("enabled")]
public void SetEnabled(ComboBox view, bool enabled)
{
view.IsEnabled = enabled;
}

/// <summary>
/// Sets the selected item.
/// </summary>
/// <param name="view">a combobox instance.</param>
/// <param name="selected">The selected item.</param>
[ReactProperty("selected")]
public void SetSelected(ComboBox view, int selected)
{
// Temporarily disable selection changed event handler.
view.SelectionChanged -= OnSelectionChanged;

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

if (view.SelectedIndex != -1)
{
view.Foreground = ((ComboBoxItem)(view.Items[view.SelectedIndex])).Foreground;
}

view.SelectionChanged += OnSelectionChanged;
}

/// <summary>
/// Populates a <see cref="ComboBox"/>
/// </summary>
/// <param name="view">a combobox instance.</param>
/// <param name="items">The picker items.</param>
[ReactProperty("items")]
public void SetItems(ComboBox view, JArray items)
{
// Temporarily disable selection changed event handler.
view.SelectionChanged -= OnSelectionChanged;

for (var index = 0; index < items.Count; index++)
{
var label = items[index].Value<JToken>("label");
if (label != null)
{
var item = new ComboBoxItem();

item.Content = label.Value<string>();
var color = items[index].Value<JToken>("color");
if (color != null)
{
var rgb = color.Value<uint>();
item.Foreground = new SolidColorBrush(ColorHelpers.Parse(rgb));
}

view.Items.Add(item);
}
}

view.SelectionChanged += OnSelectionChanged;
}

/// <summary>
/// This method should return the <see cref="ReactPickerShadowNode"/>
/// which will be then used for measuring the position and size of the
/// view.
/// </summary>
/// <returns>The shadow node instance.</returns>
public override ReactPickerShadowNode CreateShadowNodeInstance()
{
return new ReactPickerShadowNode();
}

/// <summary>
/// Implement this method to receive optional extra data enqueued from
/// the corresponding instance of <see cref="ReactShadowNode"/> in
/// <see cref="ReactShadowNode.OnCollectExtraUpdates"/>.
/// </summary>
/// <param name="root">The root view.</param>
/// <param name="extraData">The extra data.</param>
public override void UpdateExtraData(ComboBox root, object extraData)
{
}

/// <summary>
/// Called when view is detached from view hierarchy and allows for
/// additional cleanup by the <see cref="ReactPickerManager"/>.
/// </summary>
/// <param name="reactContext">The react context.</param>
/// <param name="view">The view.</param>
public override void OnDropViewInstance(ThemedReactContext reactContext, ComboBox view)
{
view.SelectionChanged -= OnSelectionChanged;
}

/// <summary>
/// Creates a new view instance of type <see cref="ComboBox"/>.
/// </summary>
/// <param name="reactContext">The react context.</param>
/// <returns>The view instance.</returns>
protected override ComboBox CreateViewInstance(ThemedReactContext reactContext)
{
return new ComboBox();
}

/// <summary>
/// Subclasses can override this method to install custom event
/// emitters on the given view.
/// </summary>
/// <param name="reactContext">The react context.</param>
/// <param name="view">The view instance.</param>
protected override void AddEventEmitters(ThemedReactContext reactContext, ComboBox view)
{
view.SelectionChanged += OnSelectionChanged;
}

/// <summary>
/// Selection changed event handler.
/// </summary>
/// <param name="sender">an event sender.</param>
/// <param name="e">the event.</param>
private void OnSelectionChanged(object sender, RoutedEventArgs e)
{
var comboBox = (ComboBox)sender;
var reactContext = comboBox.GetReactContext();
reactContext.GetNativeModule<UIManagerModule>()
.EventDispatcher
.DispatchEvent(
new ReactPickerEvent(
comboBox.GetTag(),
comboBox.SelectedIndex));
}

/// <summary>
/// A picker specific event.
/// </summary>
class ReactPickerEvent : Event
{
private readonly int _selectedIndex;

public ReactPickerEvent(int viewTag, int selectedIndex)
: base(viewTag, TimeSpan.FromTicks(Environment.TickCount))
{
_selectedIndex = selectedIndex;
}

public override string EventName
{
get
{
return "topSelect";
}
}

public override void Dispatch(RCTEventEmitter eventEmitter)
{
var eventData = new JObject
{
{ "target", ViewTag },
{ "position", _selectedIndex },
};

eventEmitter.receiveEvent(ViewTag, EventName, eventData);
}
}
}
}
25 changes: 25 additions & 0 deletions ReactWindows/ReactNative/Views/Picker/ReactPickerShadowNode.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using Facebook.CSSLayout;
using ReactNative.UIManager;
using Windows.UI.Xaml.Controls;

namespace ReactNative.Views.Picker
{
/// <summary>
/// The shadow node implementation for Picker views.
/// </summary>
public class ReactPickerShadowNode : LayoutShadowNode
{
/// <summary>
/// Instantiates the <see cref="ReactPickerShadowNode"/>.
/// </summary>
public ReactPickerShadowNode()
{
MeasureFunction = MeasurePicker;
}

private static MeasureOutput MeasurePicker(CSSNode node, float width, float height)
{
return new MeasureOutput(width, 40);
}
}
}
13 changes: 13 additions & 0 deletions ReactWindows/js/Components/Picker/PickerAndroid.windows.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/**
* 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';

module.exports = require('UnimplementedView');
13 changes: 13 additions & 0 deletions ReactWindows/js/Components/Picker/PickerIOS.windows.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/**
* 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';

module.exports = require('UnimplementedView');
Loading

0 comments on commit 02b9ded

Please sign in to comment.