fbshipit-source-id: b6fc29740c6875d2e78953b8a7123890a67930f2 Co-authored-by: Sebastian McKenzie <sebmck@fb.com> Co-authored-by: John Knox <jknox@fb.com> Co-authored-by: Emil Sjölander <emilsj@fb.com> Co-authored-by: Pritesh Nandgaonkar <prit91@fb.com>
167 lines
8.1 KiB
Plaintext
167 lines
8.1 KiB
Plaintext
/*
|
|
* Copyright (c) 2004-present, Facebook, Inc.
|
|
*
|
|
* This source code is licensed under the MIT license found in the LICENSE
|
|
* file in the root directory of this source tree.
|
|
*
|
|
*/
|
|
#if FB_SONARKIT_ENABLED
|
|
|
|
#import "CKComponent+Sonar.h"
|
|
|
|
#import <ComponentKit/CKComponentAccessibility.h>
|
|
#import <ComponentKit/CKComponentController.h>
|
|
#import <ComponentKit/CKComponentInternal.h>
|
|
#import <ComponentKit/CKComponentSubclass.h>
|
|
#import <ComponentKit/CKComponentViewConfiguration.h>
|
|
#import <SonarKitLayoutPlugin/SKNamed.h>
|
|
#import <SonarKitLayoutPlugin/SKObject.h>
|
|
|
|
/** This protocol isn't actually adopted anywhere, it just lets us use the SEL below */
|
|
@protocol SonarKitLayoutComponentKitOverrideInformalProtocol
|
|
- (NSString *)sonar_componentNameOverride;
|
|
- (NSString *)sonar_componentDecorationOverride;
|
|
- (NSArray<SKNamed<NSDictionary<NSString *, NSObject *> *> *> *)sonar_additionalDataOverride;
|
|
@end
|
|
|
|
static BOOL AccessibilityContextIsDefault(CKComponentAccessibilityContext accessibilityContext) {
|
|
return accessibilityContext == CKComponentAccessibilityContext();
|
|
}
|
|
|
|
static NSDictionary<NSString *, NSObject *> *AccessibilityContextDict(CKComponentAccessibilityContext accessibilityContext) {
|
|
NSMutableDictionary<NSString *, NSObject *> *accessibilityDict = [NSMutableDictionary new];
|
|
if (accessibilityContext.isAccessibilityElement != nil) {
|
|
accessibilityDict[@"isAccessibilityElement"] = SKObject(@([accessibilityContext.isAccessibilityElement boolValue]));
|
|
}
|
|
if (accessibilityContext.accessibilityLabel.hasText()) {
|
|
accessibilityDict[@"accessibilityLabel"] = SKObject(accessibilityContext.accessibilityLabel.value());
|
|
}
|
|
if (accessibilityContext.accessibilityHint.hasText()) {
|
|
accessibilityDict[@"accessibilityHint"] = SKObject(accessibilityContext.accessibilityHint.value());
|
|
}
|
|
if (accessibilityContext.accessibilityValue.hasText()) {
|
|
accessibilityDict[@"accessibilityValue"] = SKObject(accessibilityContext.accessibilityValue.value());
|
|
}
|
|
if (accessibilityContext.accessibilityTraits != nil) {
|
|
accessibilityDict[@"accessibilityTraits"] = SKObject(@([accessibilityContext.accessibilityTraits integerValue]));
|
|
}
|
|
if (accessibilityContext.accessibilityComponentAction) {
|
|
accessibilityDict[@"accessibilityComponentAction.identifier"] = SKObject(@(accessibilityContext.accessibilityComponentAction.identifier().c_str()));
|
|
}
|
|
return accessibilityDict;
|
|
}
|
|
|
|
FB_LINKABLE(CKComponent_Sonar)
|
|
@implementation CKComponent (Sonar)
|
|
|
|
- (NSString *)sonar_getName
|
|
{
|
|
if ([self respondsToSelector:@selector(sonar_componentNameOverride)]) {
|
|
return [(id)self sonar_componentNameOverride];
|
|
}
|
|
return NSStringFromClass([self class]);
|
|
}
|
|
|
|
- (NSString *)sonar_getDecoration
|
|
{
|
|
if ([self respondsToSelector:@selector(sonar_componentDecorationOverride)]) {
|
|
return [(id)self sonar_componentDecorationOverride];
|
|
}
|
|
return @"componentkit";
|
|
}
|
|
|
|
- (NSArray<SKNamed<NSDictionary<NSString *, NSObject *> *> *> *)sonar_getData
|
|
{
|
|
static NSDictionary<NSNumber *, NSString *> *UIControlEventsEnumMap = @{
|
|
@(UIControlEventTouchDown): @"UIControlEventTouchDown",
|
|
@(UIControlEventTouchDownRepeat): @"UIControlEventTouchDownRepeat",
|
|
@(UIControlEventTouchDragInside): @"UIControlEventTouchDragInside",
|
|
@(UIControlEventTouchDragOutside): @"UIControlEventTouchDragOutside",
|
|
@(UIControlEventTouchDragEnter): @"UIControlEventTouchDragEnter",
|
|
@(UIControlEventTouchDragExit): @"UIControlEventTouchDragExit",
|
|
@(UIControlEventTouchUpInside): @"UIControlEventTouchUpInside",
|
|
@(UIControlEventTouchUpOutside): @"UIControlEventTouchUpOutside",
|
|
@(UIControlEventTouchCancel): @"UIControlEventTouchTouchCancel",
|
|
|
|
@(UIControlEventValueChanged): @"UIControlEventValueChanged",
|
|
@(UIControlEventPrimaryActionTriggered): @"UIControlEventPrimaryActionTriggered",
|
|
|
|
@(UIControlEventEditingDidBegin): @"UIControlEventEditingDidBegin",
|
|
@(UIControlEventEditingChanged): @"UIControlEventEditingChanged",
|
|
@(UIControlEventEditingDidEnd): @"UIControlEventEditingDidEnd",
|
|
@(UIControlEventEditingDidEndOnExit): @"UIControlEventEditingDidEndOnExit",
|
|
};
|
|
|
|
|
|
NSMutableArray<SKNamed<NSDictionary<NSString *, NSObject *> *> *> *data = [NSMutableArray new];
|
|
|
|
[data addObject: [SKNamed newWithName: @"CKComponent"
|
|
withValue: @{
|
|
@"frame": SKObject(self.viewContext.frame),
|
|
@"controller": SKObject(NSStringFromClass([self.controller class])),
|
|
}]];
|
|
|
|
if (self.viewContext.view) {
|
|
auto _actions = _CKComponentDebugControlActionsForComponent(self);
|
|
if (_actions.size() > 0) {
|
|
NSMutableDictionary<NSString *, NSObject *> *actions = [NSMutableDictionary new];
|
|
|
|
for (NSNumber *controlEvent : [UIControlEventsEnumMap allKeys]) {
|
|
NSMutableArray<NSDictionary<NSString *, NSObject *> *> *responders = [NSMutableArray new];
|
|
|
|
for (const auto action : _actions) {
|
|
if ((action.first & [controlEvent integerValue]) == 0) {
|
|
continue;
|
|
}
|
|
|
|
for (auto responder : action.second) {
|
|
id initialTarget = _CKTypedComponentDebugInitialTarget(responder).get(self);
|
|
const CKActionInfo actionInfo = CKActionFind(responder.selector(), initialTarget);
|
|
[responders addObject: @{
|
|
@"initialTarget": SKObject(NSStringFromClass([initialTarget class])),
|
|
@"identifier": SKObject(@(responder.identifier().c_str())),
|
|
@"handler": SKObject(NSStringFromClass([actionInfo.responder class])),
|
|
@"selector": SKObject(NSStringFromSelector(responder.selector())),
|
|
}];
|
|
}
|
|
}
|
|
|
|
if (responders.count > 0) {
|
|
actions[UIControlEventsEnumMap[controlEvent]] = responders;
|
|
}
|
|
}
|
|
|
|
[data addObject: [SKNamed newWithName: @"Actions" withValue: actions]];
|
|
}
|
|
}
|
|
|
|
// Only add accessibility panel if accessibilityContext is not default
|
|
CKComponentAccessibilityContext accessibilityContext = [self viewConfiguration].accessibilityContext();
|
|
if (!AccessibilityContextIsDefault(accessibilityContext)) {
|
|
[data addObject:
|
|
[SKNamed newWithName: @"Accessibility"
|
|
withValue: @{
|
|
@"accessibilityContext": AccessibilityContextDict(accessibilityContext),
|
|
@"accessibilityEnabled": SKMutableObject(@(CK::Component::Accessibility::IsAccessibilityEnabled())),
|
|
}]];
|
|
}
|
|
|
|
if ([self respondsToSelector:@selector(sonar_additionalDataOverride)]) {
|
|
[data addObjectsFromArray:[(id)self sonar_additionalDataOverride]];
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
- (NSDictionary<NSString *, SKNodeUpdateData> *)sonar_getDataMutations {
|
|
return @{
|
|
@"CKComponentAccessibility.accessibilityEnabled": ^(NSNumber *value) {
|
|
CK::Component::Accessibility::SetForceAccessibilityEnabled([value boolValue]);
|
|
}
|
|
};
|
|
}
|
|
|
|
@end
|
|
|
|
#endif
|