iOS/Plugins/FlipperKitLayoutPlugin/FlipperKitLayoutComponentKitSupport/SKComponentLayoutWrapper.mm (123 lines of code) (raw):

/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * 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 "SKComponentLayoutWrapper.h" #import <ComponentKit/CKAnalyticsListenerHelpers.h> #import <ComponentKit/CKComponent.h> #import <ComponentKit/CKComponentAttachController.h> #import <ComponentKit/CKComponentAttachControllerInternal.h> #import <ComponentKit/CKComponentInternal.h> #import <ComponentKit/CKComponentRootView.h> #import <ComponentKit/CKInspectableView.h> #import "CKComponent+Sonar.h" #import "SKComponentMountedView.h" static char const kLayoutWrapperKey = ' '; static CK::Optional<CKFlexboxComponentChild> findFlexboxLayoutParams( id<CKMountable> parent, id<CKMountable> child) { if ([parent isKindOfClass:[CKFlexboxComponent class]]) { static Ivar ivar = class_getInstanceVariable([CKFlexboxComponent class], "_children"); static ptrdiff_t offset = ivar_getOffset(ivar); unsigned char* pComponent = (unsigned char*)(__bridge void*)parent; auto children = (std::vector<CKFlexboxComponentChild>*)(pComponent + offset); if (children) { for (auto it = children->begin(); it != children->end(); it++) { if (it->component == child) { return *it; } } } } return CK::none; } @implementation SKComponentLayoutWrapper + (instancetype)newFromRoot:(id<CKInspectableView>)root parentKey:(NSString*)parentKey { const auto layout = [root mountedLayout]; // Check if there is a cached wrapper. if (layout.component) { SKComponentLayoutWrapper* cachedWrapper = objc_getAssociatedObject(layout.component, &kLayoutWrapperKey); if (cachedWrapper) { return cachedWrapper; } } // TODO: Add support for `CKMountable` components. CKComponent* component = (CKComponent*)layout.component; CKComponentReuseWrapper* reuseWrapper = CKAnalyticsListenerHelpers::GetReusedNodes(component); // Create a new layout wrapper. SKComponentLayoutWrapper* const wrapper = [[SKComponentLayoutWrapper alloc] initWithLayout:layout position:CGPointMake(0, 0) flexboxChild:CK::none parentKey:[NSString stringWithFormat:@"%@%d.", parentKey, component.treeNode.nodeIdentifier] reuseWrapper:reuseWrapper rootNode:root]; // Cache the result. if (component) { objc_setAssociatedObject( component, &kLayoutWrapperKey, wrapper, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } return wrapper; } - (instancetype)initWithLayout:(const CKComponentLayout&)layout position:(CGPoint)position flexboxChild: (CK::Optional<CKFlexboxComponentChild>)flexboxChild parentKey:(NSString*)parentKey reuseWrapper:(CKComponentReuseWrapper*)reuseWrapper rootNode:(id<CKInspectableView>)node { if (self = [super init]) { _rootNode = node; _component = (CKComponent*)layout.component; _size = layout.size; _position = position; _flexboxChild = flexboxChild; _identifier = [parentKey stringByAppendingString:layout.component ? layout.component.className : @"(null)"]; if (_component && reuseWrapper) { auto const canBeReusedCounter = [reuseWrapper canBeReusedCounter:_component.treeNode.nodeIdentifier]; if (canBeReusedCounter > 0) { _component.flipper_canBeReusedCounter = canBeReusedCounter; } } std::vector<SKComponentLayoutWrapper*> childComponents; if (layout.children != nullptr) { int index = 0; for (const auto& child : *layout.children) { if (child.layout.component == nil) { continue; // nil children are allowed, ignore them } SKComponentLayoutWrapper* childWrapper = [[SKComponentLayoutWrapper alloc] initWithLayout:child.layout position:child.position flexboxChild:findFlexboxLayoutParams( _component, child.layout.component) parentKey:[_identifier stringByAppendingFormat:@"[%d].", index++] reuseWrapper:reuseWrapper rootNode:node]; childComponents.push_back(childWrapper); } } UIView* mountedView = _component.mountedView; if (mountedView && !childComponents.empty()) { _children = SKMountedViewChild{[[SKComponentMountedView alloc] initWithView:mountedView children:childComponents]}; } else if (mountedView) { _children = SKLeafViewChild{mountedView}; // leaf view } else { _children = childComponents; } } return self; } @end #endif