From cd54b619bd7c3d65c458741a519e497d14ee18e6 Mon Sep 17 00:00:00 2001 From: Eric Rozell Date: Thu, 24 Dec 2015 14:15:05 -0500 Subject: [PATCH] Fixes #32 - Adds UIManagerModule constants Some remaining TODOs include integrating the constants from the view managers, and further investigation on how to include other features available in Android. --- .../Bridge/JavaScriptModuleRegistryTests.cs | 2 +- .../UIManager/Events/RCTEventEmitterTests.cs | 2 +- .../ReactNative/CoreModulesPackage.cs | 1 + ReactWindows/ReactNative/ReactNative.csproj | 4 + .../UIManager/Events/RCTEventEmitter.cs | 2 +- .../UIManager/Events/TouchEventType.cs | 29 ++ .../Events/TouchEventTypeExtensions.cs | 24 ++ .../ReactNative/UIManager/PointerEvents.cs | 30 ++ .../UIManager/UIManagerModule.Constants.cs | 260 ++++++++++++++++++ .../ReactNative/UIManager/UIManagerModule.cs | 9 +- 10 files changed, 357 insertions(+), 6 deletions(-) create mode 100644 ReactWindows/ReactNative/UIManager/Events/TouchEventType.cs create mode 100644 ReactWindows/ReactNative/UIManager/Events/TouchEventTypeExtensions.cs create mode 100644 ReactWindows/ReactNative/UIManager/PointerEvents.cs create mode 100644 ReactWindows/ReactNative/UIManager/UIManagerModule.Constants.cs diff --git a/ReactWindows/ReactNative.Tests/Bridge/JavaScriptModuleRegistryTests.cs b/ReactWindows/ReactNative.Tests/Bridge/JavaScriptModuleRegistryTests.cs index 3e816c4a681..2275210dafd 100644 --- a/ReactWindows/ReactNative.Tests/Bridge/JavaScriptModuleRegistryTests.cs +++ b/ReactWindows/ReactNative.Tests/Bridge/JavaScriptModuleRegistryTests.cs @@ -2,8 +2,8 @@ using Newtonsoft.Json; using Newtonsoft.Json.Linq; using ReactNative.Bridge; -using ReactNative.Modules.Core; using ReactNative.UIManager; +using ReactNative.UIManager.Events; using System; using System.Collections.Generic; using System.Threading; diff --git a/ReactWindows/ReactNative.Tests/UIManager/Events/RCTEventEmitterTests.cs b/ReactWindows/ReactNative.Tests/UIManager/Events/RCTEventEmitterTests.cs index 0aa914c28f7..ed028631409 100644 --- a/ReactWindows/ReactNative.Tests/UIManager/Events/RCTEventEmitterTests.cs +++ b/ReactWindows/ReactNative.Tests/UIManager/Events/RCTEventEmitterTests.cs @@ -1,6 +1,6 @@ using Microsoft.VisualStudio.TestPlatform.UnitTestFramework; using Newtonsoft.Json.Linq; -using ReactNative.Modules.Core; +using ReactNative.UIManager.Events; namespace ReactNative.Tests.UIManager.Events { diff --git a/ReactWindows/ReactNative/CoreModulesPackage.cs b/ReactWindows/ReactNative/CoreModulesPackage.cs index 2da15b23105..d1e48cd4538 100644 --- a/ReactWindows/ReactNative/CoreModulesPackage.cs +++ b/ReactWindows/ReactNative/CoreModulesPackage.cs @@ -2,6 +2,7 @@ using ReactNative.Modules.Core; using ReactNative.Tracing; using ReactNative.UIManager; +using ReactNative.UIManager.Events; using System; using System.Collections.Generic; using Windows.UI.Xaml; diff --git a/ReactWindows/ReactNative/ReactNative.csproj b/ReactWindows/ReactNative/ReactNative.csproj index 815572af38e..91f0d85b949 100644 --- a/ReactWindows/ReactNative/ReactNative.csproj +++ b/ReactWindows/ReactNative/ReactNative.csproj @@ -201,6 +201,9 @@ + + + @@ -211,6 +214,7 @@ + diff --git a/ReactWindows/ReactNative/UIManager/Events/RCTEventEmitter.cs b/ReactWindows/ReactNative/UIManager/Events/RCTEventEmitter.cs index 06e98e780dc..b4981ea83a1 100644 --- a/ReactWindows/ReactNative/UIManager/Events/RCTEventEmitter.cs +++ b/ReactWindows/ReactNative/UIManager/Events/RCTEventEmitter.cs @@ -1,7 +1,7 @@ using Newtonsoft.Json.Linq; using ReactNative.Bridge; -namespace ReactNative.Modules.Core +namespace ReactNative.UIManager.Events { /// /// JavaScript event emitter. diff --git a/ReactWindows/ReactNative/UIManager/Events/TouchEventType.cs b/ReactWindows/ReactNative/UIManager/Events/TouchEventType.cs new file mode 100644 index 00000000000..4d6da72d38c --- /dev/null +++ b/ReactWindows/ReactNative/UIManager/Events/TouchEventType.cs @@ -0,0 +1,29 @@ +namespace ReactNative.UIManager.Events +{ + /// + /// Touch event types that the JavaScript module + /// understands. + /// + public enum TouchEventType + { + /// + /// Touch start event type. + /// + Start, + + /// + /// Touch end event type. + /// + End, + + /// + /// Touch move event type. + /// + Move, + + /// + /// Touch cancel event type. + /// + Cancel, + } +} diff --git a/ReactWindows/ReactNative/UIManager/Events/TouchEventTypeExtensions.cs b/ReactWindows/ReactNative/UIManager/Events/TouchEventTypeExtensions.cs new file mode 100644 index 00000000000..95b14aa07ae --- /dev/null +++ b/ReactWindows/ReactNative/UIManager/Events/TouchEventTypeExtensions.cs @@ -0,0 +1,24 @@ +using System; + +namespace ReactNative.UIManager.Events +{ + static class TouchEventTypeExtensions + { + public static string GetJavaScriptEventName(this TouchEventType eventType) + { + switch (eventType) + { + case TouchEventType.Start: + return "topTouchStart"; + case TouchEventType.End: + return "topTouchEnd"; + case TouchEventType.Move: + return "topTouchMove"; + case TouchEventType.Cancel: + return "topTouchCancel"; + default: + throw new NotSupportedException("Unsupported touch event type."); + } + } + } +} diff --git a/ReactWindows/ReactNative/UIManager/PointerEvents.cs b/ReactWindows/ReactNative/UIManager/PointerEvents.cs new file mode 100644 index 00000000000..46eb00f42b9 --- /dev/null +++ b/ReactWindows/ReactNative/UIManager/PointerEvents.cs @@ -0,0 +1,30 @@ +namespace ReactNative.UIManager +{ + /// + /// Possible values for pointer events that a view and its descendants should + /// receive. See https://developer.mozilla.org/en-US/docs/Web/CSS/pointer-events + /// for more information. + /// + public enum PointerEvents + { + /// + /// Neither the container nor its children receive events. + /// + None, + + /// + /// Container does not get events but all its children do. + /// + BoxNone, + + /// + /// Container gets events but none of its children do. + /// + BoxOnly, + + /// + /// Container and all of its children receive touch events. + /// + Auto, + } +} diff --git a/ReactWindows/ReactNative/UIManager/UIManagerModule.Constants.cs b/ReactWindows/ReactNative/UIManager/UIManagerModule.Constants.cs new file mode 100644 index 00000000000..ede80c6a214 --- /dev/null +++ b/ReactWindows/ReactNative/UIManager/UIManagerModule.Constants.cs @@ -0,0 +1,260 @@ +using ReactNative.UIManager.Events; +using System.Collections.Generic; + +namespace ReactNative.UIManager +{ + using Windows.UI.Xaml; + using Map = Dictionary; + + public partial class UIManagerModule + { + private const string CUSTOM_BUBBLING_EVENT_TYPES_KEY = "customBubblingEventTypes"; + private const string CUSTOM_DIRECT_EVENT_TYPES_KEY = "customDirectEventTypes"; + + public const string ACTION_DISMISSED = "dismissed"; + public const string ACTION_ITEM_SELECTED = "itemSelected"; + + public static IDictionary CreateConstants(IReadOnlyList> viewManagers) + { + var constants = GetConstants(); + var bubblingEventTypesConstants = GetBubblingEventTypeConstants(); + var directEventTypesConstants = GetDirectEventTypeConstants(); + + foreach (var viewManager in viewManagers) + { + // TODO: add view manager exports + } + + constants.Add(CUSTOM_BUBBLING_EVENT_TYPES_KEY, bubblingEventTypesConstants); + constants.Add(CUSTOM_DIRECT_EVENT_TYPES_KEY, directEventTypesConstants); + + return constants; + } + + public static IDictionary GetBubblingEventTypeConstants() + { + return new Map + { + { + "topChange", + new Map + { + { + "phasedRegistrationNames", + new Map + { + { "bubbled", "onChange" }, + { "captured", "onChangeCapture" }, + } + } + } + }, + { + "topSelect", + new Map + { + { + "phasedRegistrationNames", + new Map + { + { "bubbled", "onSelect" }, + { "captured", "onSelectCapture" }, + } + } + } + }, + { + TouchEventType.Start.GetJavaScriptEventName(), + new Map + { + { + "phasedRegistrationName", + new Map + { + { "bubbled", "onTouchStart" }, + { "captured", "onTouchStartCapture" }, + } + } + } + }, + { + TouchEventType.Move.GetJavaScriptEventName(), + new Map + { + { + "phasedRegistrationName", + new Map + { + { "bubbled", "onTouchMove" }, + { "captured", "onTouchMoveCapture" }, + } + } + } + }, + { + TouchEventType.Start.GetJavaScriptEventName(), + new Map + { + { + "phasedRegistrationName", + new Map + { + { "bubbled", "onTouchEnd" }, + { "captured", "onTouchEndCapture" }, + } + } + } + }, + }; + } + + public static IDictionary GetDirectEventTypeConstants() + { + return new Map + { + { + "topSelectionChange", + new Map + { + { "registrationName", "onSelectionChange" }, + } + }, + { + "topLoadingStart", + new Map + { + { "registrationName", "onLoadingStart" }, + } + }, + { + "topLoadingFinish", + new Map + { + { "registrationName", "onLoadingFinish" }, + } + }, + { + "topLoadingError", + new Map + { + { "registrationName", "onLoadingError" }, + } + }, + { + "topLayout", + new Map + { + { "registrationName", "onLayout" }, + } + }, + }; + } + + public static IDictionary GetConstants() + { + return new Map + { + { + "UIView", + new Map + { + { + "ContentMode", + new Map + { + /* TODO: declare content mode properties */ + } + }, + } + }, + { + "UIText", + new Map + { + { + "AutocapitalizationType", + new Map + { + /* TODO: declare capitalization types */ + } + }, + } + }, + { + "Dimensions", + new Map + { + { + "window", + new Dictionary + { + { "width", 100 }, + { "height", 100 }, + { "scale", 1 }, + /* TODO: verify values? */ + /* TODO: density and DPI needed? */ + } + }, + } + }, + { + "StyleConstants", + new Map + { + { + "PointerEventsValues", + new Map + { + { "none", PointerEvents.None.ToString() }, + { "boxNone", PointerEvents.BoxNone.ToString() }, + { "boxOnly", PointerEvents.BoxOnly.ToString() }, + { "unspecified", PointerEvents.Auto.ToString() }, + } + }, + } + }, + { + "PopupMenu", + new Map + { + { ACTION_DISMISSED, ACTION_DISMISSED }, + { ACTION_ITEM_SELECTED, ACTION_ITEM_SELECTED }, + } + }, + { + "AccessibilityEventTypes", + new Map + { + /* TODO: declare accessibility event types */ + } + }, + }; + } + + private static void RecursiveMerge(IDictionary sink, IDictionary source) + { + foreach (var pair in source) + { + var existing = default(object); + if (sink.TryGetValue(pair.Key, out existing)) + { + var sourceAsMap = pair.Value as IDictionary; + var sinkAsMap = existing as IDictionary; + if (sourceAsMap != null && sinkAsMap != null) + { + RecursiveMerge(sinkAsMap, sourceAsMap); + } + else + { + // TODO: replace with exception? + sink.Add(pair.Key, pair.Value); + } + } + else + { + sink.Add(pair.Key, pair.Value); + } + } + } + } +} diff --git a/ReactWindows/ReactNative/UIManager/UIManagerModule.cs b/ReactWindows/ReactNative/UIManager/UIManagerModule.cs index a0cb9480a47..53117166df9 100644 --- a/ReactWindows/ReactNative/UIManager/UIManagerModule.cs +++ b/ReactWindows/ReactNative/UIManager/UIManagerModule.cs @@ -9,16 +9,19 @@ namespace ReactNative.UIManager /// /// Native module to allow JS to create and update native Views. /// - public class UIManagerModule : NativeModuleBase + public partial class UIManagerModule : NativeModuleBase { - private readonly UIImplementation _UIImplementation; + private readonly UIImplementation _uiImplementation; + private readonly IDictionary _moduleConstants; + private int nextRootTag = 1; public UIManagerModule(ReactApplicationContext reactContext, IReadOnlyList> viewManagerList, UIImplementation uiImplementation) { - _UIImplementation = uiImplementation; + _uiImplementation = uiImplementation; + _moduleConstants = CreateConstants(viewManagerList); } public override string Name