Simplified event registration

Summary:
Our events all follow a common pattern, so there's no good reason why the configuration should be so verbose. This diff eliminates that redundancy, and gives us the freedom to simplify the underlying mechanism in future without further churning the call sites.
This commit is contained in:
Nick Lockwood
2015-08-11 06:37:12 -07:00
parent 2fe1ac2a83
commit 48af214216
25 changed files with 208 additions and 266 deletions

View File

@@ -53,7 +53,7 @@ RCT_REMAP_VIEW_PROPERTY(timeZoneOffsetInMinutes, timeZone, NSTimeZone)
@"target": sender.reactTag,
@"timestamp": @([sender.date timeIntervalSince1970] * 1000.0)
};
[self.bridge.eventDispatcher sendInputEventWithName:@"topChange" body:event];
[self.bridge.eventDispatcher sendInputEventWithName:@"change" body:event];
}
- (NSDictionary *)constantsToExport

View File

@@ -75,7 +75,7 @@ RCT_CUSTOM_VIEW_PROPERTY(region, MKCoordinateRegion, RCTMap)
}
};
[self.bridge.eventDispatcher sendInputEventWithName:@"topTap" body:event];
[self.bridge.eventDispatcher sendInputEventWithName:@"press" body:event];
}
}
@@ -116,7 +116,7 @@ RCT_CUSTOM_VIEW_PROPERTY(region, MKCoordinateRegion, RCTMap)
@"annotationId": annotation.identifier
};
[self.bridge.eventDispatcher sendInputEventWithName:@"topTap" body:event];
[self.bridge.eventDispatcher sendInputEventWithName:@"press" body:event];
}
@@ -222,7 +222,7 @@ RCT_CUSTOM_VIEW_PROPERTY(region, MKCoordinateRegion, RCTMap)
@"longitudeDelta": @(FLUSH_NAN(region.span.longitudeDelta)),
}
};
[self.bridge.eventDispatcher sendInputEventWithName:@"topChange" body:event];
[self.bridge.eventDispatcher sendInputEventWithName:@"change" body:event];
}
@end

View File

@@ -308,7 +308,7 @@ RCT_NOT_IMPLEMENTED(-initWithCoder:(NSCoder *)aDecoder)
return;
}
_mostRecentProgress = nextProgress;
[_bridge.eventDispatcher sendInputEventWithName:@"topNavigationProgress" body:@{
[_bridge.eventDispatcher sendInputEventWithName:@"navigationProgress" body:@{
@"fromIndex": @(_currentlyTransitioningFrom),
@"toIndex": @(_currentlyTransitioningTo),
@"progress": @(nextProgress),
@@ -416,7 +416,7 @@ RCT_NOT_IMPLEMENTED(-initWithCoder:(NSCoder *)aDecoder)
- (void)handleTopOfStackChanged
{
[_bridge.eventDispatcher sendInputEventWithName:@"topNavigateBack" body:@{
[_bridge.eventDispatcher sendInputEventWithName:@"navigationComplete" body:@{
@"target":self.reactTag,
@"stackLength":@(_navigationController.viewControllers.count)
}];

View File

@@ -26,13 +26,20 @@ RCT_EXPORT_MODULE()
RCT_EXPORT_VIEW_PROPERTY(requestedTopOfStack, NSInteger)
- (NSDictionary *)customDirectEventTypes
- (NSArray *)customBubblingEventTypes
{
return @{
@"topNavigationProgress": @{
@"registrationName": @"onNavigationProgress"
},
};
return @[
@"navigationComplete",
@"navLeftButtonTap",
@"navRightButtonTap",
];
}
- (NSArray *)customDirectEventTypes
{
return @[
@"navigationProgress",
];
}
// TODO: remove error callbacks

View File

@@ -100,7 +100,7 @@ numberOfRowsInComponent:(__unused NSInteger)component
@"newValue": [self valueForRow:row]
};
[_eventDispatcher sendInputEventWithName:@"topChange" body:event];
[_eventDispatcher sendInputEventWithName:@"change" body:event];
}
@end

View File

@@ -98,12 +98,12 @@ RCT_NOT_IMPLEMENTED(-init)
- (NSString *)eventName
{
static NSString *events[] = {
@"topScrollBeginDrag",
@"topScroll",
@"topScrollEndDrag",
@"topMomentumScrollBegin",
@"topMomentumScrollEnd",
@"topScrollAnimationEnd",
@"scrollBeginDrag",
@"scroll",
@"scrollEndDrag",
@"momentumScrollBegin",
@"momentumScrollEnd",
@"scrollAnimationEnd",
};
return events[_type];
@@ -123,7 +123,7 @@ RCT_NOT_IMPLEMENTED(-init)
userData[@"updatedChildFrames"] = updatedChildFrames;
newEvent->_userData = userData;
}
return newEvent;
}

View File

@@ -111,4 +111,16 @@ RCT_EXPORT_METHOD(calculateChildFrames:(nonnull NSNumber *)reactTag
}];
}
- (NSArray *)customDirectEventTypes
{
return @[
@"scrollBeginDrag",
@"scroll",
@"scrollEndDrag",
@"scrollAnimationEnd",
@"momentumScrollBegin",
@"momentumScrollEnd",
];
}
@end

View File

@@ -52,7 +52,7 @@
@"value": [self titleForSegmentAtIndex:sender.selectedSegmentIndex],
@"selectedSegmentIndex": @(sender.selectedSegmentIndex)
};
[_eventDispatcher sendInputEventWithName:@"topChange" body:event];
[_eventDispatcher sendInputEventWithName:@"change" body:event];
}
@end

View File

@@ -35,7 +35,7 @@ static void RCTSendSliderEvent(RCTSliderManager *self, UISlider *sender, BOOL co
@"continuous": @(continuous),
};
[self.bridge.eventDispatcher sendInputEventWithName:@"topChange" body:event];
[self.bridge.eventDispatcher sendInputEventWithName:@"change" body:event];
}
- (void)sliderValueChanged:(UISlider *)sender

View File

@@ -30,7 +30,7 @@ RCT_EXPORT_MODULE()
- (void)onChange:(RCTSwitch *)sender
{
if (sender.wasOn != sender.on) {
[self.bridge.eventDispatcher sendInputEventWithName:@"topChange" body:@{
[self.bridge.eventDispatcher sendInputEventWithName:@"change" body:@{
@"target": sender.reactTag,
@"value": @(sender.on)
}];

View File

@@ -154,7 +154,7 @@ RCT_NOT_IMPLEMENTED(-initWithCoder:(NSCoder *)aDecoder)
{
NSUInteger index = [tabBarController.viewControllers indexOfObject:viewController];
RCTTabBarItem *tab = [self reactSubviews][index];
[_eventDispatcher sendInputEventWithName:@"topTap" body:@{@"target": tab.reactTag}];
[_eventDispatcher sendInputEventWithName:@"press" body:@{@"target": tab.reactTag}];
return NO;
}

View File

@@ -48,40 +48,27 @@ typedef void (^RCTViewManagerUIBlock)(RCTUIManager *uiManager, RCTSparseArray *v
- (RCTShadowView *)shadowView;
/**
* Returns a dictionary of config data passed to JS that defines eligible events
* that can be placed on native views. This should return bubbling
* directly-dispatched event types and specify what names should be used to
* subscribe to either form (bubbling/capturing).
*
* Returned dictionary should be of the form: @{
* @"onTwirl": {
* @"phasedRegistrationNames": @{
* @"bubbled": @"onTwirl",
* @"captured": @"onTwirlCaptured"
* }
* }
* }
* Returns an array of names of events that can be sent by native views. This
* should return bubbling, directly-dispatched event types. The event name
* should not include a prefix such as 'on' or 'top', as this will be applied
* as needed. When subscribing to the event, use the 'Captured' suffix to
* indicate the captured form, or omit the suffix for the bubbling form.
*
* Note that this method is not inherited when you subclass a view module, and
* you should not call [super customBubblingEventTypes] when overriding it.
*/
- (NSDictionary *)customBubblingEventTypes;
- (NSArray *)customBubblingEventTypes;
/**
* Returns a dictionary of config data passed to JS that defines eligible events
* that can be placed on native views. This should return non-bubbling
* directly-dispatched event types.
*
* Returned dictionary should be of the form: @{
* @"onTwirl": {
* @"registrationName": @"onTwirl"
* }
* }
* Returns an array of names of events that can be sent by native views. This
* should return non-bubbling, directly-dispatched event types. The event name
* should not include a prefix such as 'on' or 'top', as this will be applied
* as needed.
*
* Note that this method is not inherited when you subclass a view module, and
* you should not call [super customDirectEventTypes] when overriding it.
*/
- (NSDictionary *)customDirectEventTypes;
- (NSArray *)customDirectEventTypes;
/**
* Called to notify manager that layout has finished, in case any calculated

View File

@@ -22,24 +22,24 @@
@implementation RCTConvert(UIAccessibilityTraits)
RCT_MULTI_ENUM_CONVERTER(UIAccessibilityTraits, (@{
@"none": @(UIAccessibilityTraitNone),
@"button": @(UIAccessibilityTraitButton),
@"link": @(UIAccessibilityTraitLink),
@"header": @(UIAccessibilityTraitHeader),
@"search": @(UIAccessibilityTraitSearchField),
@"image": @(UIAccessibilityTraitImage),
@"selected": @(UIAccessibilityTraitSelected),
@"plays": @(UIAccessibilityTraitPlaysSound),
@"key": @(UIAccessibilityTraitKeyboardKey),
@"text": @(UIAccessibilityTraitStaticText),
@"summary": @(UIAccessibilityTraitSummaryElement),
@"disabled": @(UIAccessibilityTraitNotEnabled),
@"frequentUpdates": @(UIAccessibilityTraitUpdatesFrequently),
@"startsMedia": @(UIAccessibilityTraitStartsMediaSession),
@"adjustable": @(UIAccessibilityTraitAdjustable),
@"allowsDirectInteraction": @(UIAccessibilityTraitAllowsDirectInteraction),
@"pageTurn": @(UIAccessibilityTraitCausesPageTurn),
}), UIAccessibilityTraitNone, unsignedLongLongValue)
@"none": @(UIAccessibilityTraitNone),
@"button": @(UIAccessibilityTraitButton),
@"link": @(UIAccessibilityTraitLink),
@"header": @(UIAccessibilityTraitHeader),
@"search": @(UIAccessibilityTraitSearchField),
@"image": @(UIAccessibilityTraitImage),
@"selected": @(UIAccessibilityTraitSelected),
@"plays": @(UIAccessibilityTraitPlaysSound),
@"key": @(UIAccessibilityTraitKeyboardKey),
@"text": @(UIAccessibilityTraitStaticText),
@"summary": @(UIAccessibilityTraitSummaryElement),
@"disabled": @(UIAccessibilityTraitNotEnabled),
@"frequentUpdates": @(UIAccessibilityTraitUpdatesFrequently),
@"startsMedia": @(UIAccessibilityTraitStartsMediaSession),
@"adjustable": @(UIAccessibilityTraitAdjustable),
@"allowsDirectInteraction": @(UIAccessibilityTraitAllowsDirectInteraction),
@"pageTurn": @(UIAccessibilityTraitCausesPageTurn),
}), UIAccessibilityTraitNone, unsignedLongLongValue)
@end
@@ -64,14 +64,34 @@ RCT_EXPORT_MODULE()
return [[RCTShadowView alloc] init];
}
- (NSDictionary *)customBubblingEventTypes
- (NSArray *)customBubblingEventTypes
{
return nil;
return @[
// Generic events
@"press",
@"change",
@"change",
@"focus",
@"blur",
@"submitEditing",
@"endEditing",
// Touch events
@"touchStart",
@"touchMove",
@"touchCancel",
@"touchEnd",
];
}
- (NSDictionary *)customDirectEventTypes
- (NSArray *)customDirectEventTypes
{
return nil;
return @[
@"layout",
@"accessibilityTap",
@"magicTap",
];
}
- (NSDictionary *)constantsToExport
@@ -172,11 +192,11 @@ RCT_CUSTOM_VIEW_PROPERTY(borderWidth, CGFloat, RCTView)
}
RCT_CUSTOM_VIEW_PROPERTY(onAccessibilityTap, BOOL, __unused RCTView)
{
view.accessibilityTapHandler = [self eventHandlerWithName:@"topAccessibilityTap" json:json];
view.accessibilityTapHandler = [self eventHandlerWithName:@"accessibilityTap" json:json];
}
RCT_CUSTOM_VIEW_PROPERTY(onMagicTap, BOOL, __unused RCTView)
{
view.magicTapHandler = [self eventHandlerWithName:@"topMagicTap" json:json];
view.magicTapHandler = [self eventHandlerWithName:@"magicTap" json:json];
}
- (RCTViewEventHandler)eventHandlerWithName:(NSString *)eventName json:(id)json

View File

@@ -151,7 +151,7 @@ RCT_NOT_IMPLEMENTED(-initWithCoder:(NSCoder *)aDecoder)
@"url": [request.URL absoluteString],
@"navigationType": @(navigationType)
}];
[_eventDispatcher sendInputEventWithName:@"topLoadingStart" body:event];
[_eventDispatcher sendInputEventWithName:@"loadingStart" body:event];
}
// JS Navigation handler
@@ -174,7 +174,7 @@ RCT_NOT_IMPLEMENTED(-initWithCoder:(NSCoder *)aDecoder)
@"code": @(error.code),
@"description": [error localizedDescription],
}];
[_eventDispatcher sendInputEventWithName:@"topLoadingError" body:event];
[_eventDispatcher sendInputEventWithName:@"loadingError" body:event];
}
- (void)webViewDidFinishLoad:(UIWebView *)webView
@@ -185,7 +185,7 @@ RCT_NOT_IMPLEMENTED(-initWithCoder:(NSCoder *)aDecoder)
// we only need the final 'finishLoad' call so only fire the event when we're actually done loading.
if (!webView.loading && ![webView.request.URL.absoluteString isEqualToString:@"about:blank"]) {
[_eventDispatcher sendInputEventWithName:@"topLoadingFinish" body:[self baseEvent]];
[_eventDispatcher sendInputEventWithName:@"loadingFinish" body:[self baseEvent]];
}
}

View File

@@ -32,6 +32,15 @@ RCT_EXPORT_VIEW_PROPERTY(injectedJavaScript, NSString);
RCT_EXPORT_VIEW_PROPERTY(contentInset, UIEdgeInsets);
RCT_EXPORT_VIEW_PROPERTY(automaticallyAdjustContentInsets, BOOL);
- (NSArray *)customDirectEventTypes
{
return @[
@"loadingStart",
@"loadingFinish",
@"loadingError",
];
}
- (NSDictionary *)constantsToExport
{
return @{

View File

@@ -124,13 +124,13 @@ static UIView *RCTFindNavBarShadowViewInView(UIView *view)
- (void)handleNavLeftButtonTapped
{
[_eventDispatcher sendInputEventWithName:@"topNavLeftButtonTap"
[_eventDispatcher sendInputEventWithName:@"navLeftButtonTap"
body:@{@"target":_navItem.reactTag}];
}
- (void)handleNavRightButtonTapped
{
[_eventDispatcher sendInputEventWithName:@"topNavRightButtonTap"
[_eventDispatcher sendInputEventWithName:@"navRightButtonTap"
body:@{@"target":_navItem.reactTag}];
}