UNPKG

nitro-codegen

Version:

The code-generator for react-native-nitro-modules.

133 lines (114 loc) 4.67 kB
import { createViewComponentShadowNodeFiles, getViewComponentNames, } from '../CppHybridViewComponent.js'; import { createFileMetadataString, escapeCppName, } from '../../syntax/helpers.js'; import { NitroConfig } from '../../config/NitroConfig.js'; import { getUmbrellaHeaderName } from '../../autolinking/ios/createSwiftUmbrellaHeader.js'; import { getHybridObjectName } from '../../syntax/getHybridObjectName.js'; import { getHybridObjectConstructorCall } from '../../syntax/swift/SwiftHybridObjectRegistration.js'; import { indent } from '../../utils.js'; import { SwiftCxxBridgedType } from '../../syntax/swift/SwiftCxxBridgedType.js'; export function createSwiftHybridViewManager(spec) { const cppFiles = createViewComponentShadowNodeFiles(spec); const namespace = NitroConfig.getCxxNamespace('c++'); const swiftNamespace = NitroConfig.getIosModuleName(); const { HybridTSpec, HybridTSpecSwift, HybridTSpecCxx } = getHybridObjectName(spec.name); const { component, descriptorClassName, propsClassName } = getViewComponentNames(spec); const autolinking = NitroConfig.getAutolinkedHybridObjects(); const viewImplementation = autolinking[spec.name]?.swift; if (viewImplementation == null) { throw new Error(`Cannot create Swift HybridView ViewManager for ${spec.name} - it is not autolinked in nitro.json!`); } const propAssignments = spec.properties.map((p) => { const name = escapeCppName(p.name); const setter = p.getSetterName('swift'); const bridge = new SwiftCxxBridgedType(p.type, false); const parse = bridge.parseFromCppToSwift(`newViewProps.${name}.value`, 'c++'); return ` // ${p.jsSignature} if (newViewProps.${name}.isDirty) { swiftPart.${setter}(${indent(parse, ' ')}); newViewProps.${name}.isDirty = false; } `.trim(); }); const mmFile = ` ${createFileMetadataString(`${component}.mm`)} #import "${component}.hpp" #import <memory> #import <react/renderer/componentregistry/ComponentDescriptorProvider.h> #import <React/RCTViewComponentView.h> #import <React/RCTComponentViewFactory.h> #import <React/UIView+ComponentViewProtocol.h> #import <NitroModules/NitroDefines.hpp> #import <UIKit/UIKit.h> #import "${HybridTSpecSwift}.hpp" #import "${getUmbrellaHeaderName()}" using namespace facebook; using namespace ${namespace}; using namespace ${namespace}::views; /** * Represents the React Native View holder for the Nitro "${spec.name}" HybridView. */ @interface ${component}: RCTViewComponentView @end @implementation ${component} { std::shared_ptr<${HybridTSpecSwift}> _hybridView; } + (void) load { [super load]; [RCTComponentViewFactory.currentComponentViewFactory registerComponentViewClass:[${component} class]]; } + (react::ComponentDescriptorProvider) componentDescriptorProvider { return react::concreteComponentDescriptorProvider<${descriptorClassName}>(); } - (instancetype) init { if (self = [super init]) { std::shared_ptr<${HybridTSpec}> hybridView = ${getHybridObjectConstructorCall(spec.name)} _hybridView = std::dynamic_pointer_cast<${HybridTSpecSwift}>(hybridView); [self updateView]; } return self; } - (void) updateView { // 1. Get Swift part ${swiftNamespace}::${HybridTSpecCxx}& swiftPart = _hybridView->getSwiftPart(); // 2. Get UIView* void* viewUnsafe = swiftPart.getView(); UIView* view = (__bridge_transfer UIView*) viewUnsafe; // 3. Update RCTViewComponentView's [contentView] [self setContentView:view]; } - (void) updateProps:(const react::Props::Shared&)props oldProps:(const react::Props::Shared&)oldProps { // 1. Downcast props const auto& newViewPropsConst = *std::static_pointer_cast<${propsClassName} const>(props); auto& newViewProps = const_cast<${propsClassName}&>(newViewPropsConst); ${swiftNamespace}::${HybridTSpecCxx}& swiftPart = _hybridView->getSwiftPart(); // 2. Update each prop individually swiftPart.beforeUpdate(); ${indent(propAssignments.join('\n'), ' ')} swiftPart.afterUpdate(); // 3. Update hybridRef if it changed if (newViewProps.hybridRef.isDirty) { // hybridRef changed - call it with new this const auto& maybeFunc = newViewProps.hybridRef.value; if (maybeFunc.has_value()) { maybeFunc.value()(_hybridView); } newViewProps.hybridRef.isDirty = false; } // 4. Continue in base class [super updateProps:props oldProps:oldProps]; } @end `; return [ ...cppFiles, { content: mmFile, language: 'c++', name: `${component}.mm`, platform: 'ios', subdirectory: ['views'], }, ]; }