From 8e56d0bcb362d58d449fe86221d75467fcbc31a2 Mon Sep 17 00:00:00 2001 From: Marc Rousavy Date: Thu, 16 Jan 2025 02:24:09 +0100 Subject: [PATCH] feat: Generate view config as .json --- .../src/views/CppHybridViewComponent.ts | 6 +++- .../src/views/createHostComponentJs.ts | 32 +++++++++++++++++++ .../ios/c++/views/HybridTestViewComponent.mm | 2 ++ .../generated/shared/json/TestViewConfig.json | 10 ++++++ .../src/views/TestView.ts | 7 ++++ .../src/views/getHostComponent.ts | 11 +++++-- 6 files changed, 64 insertions(+), 4 deletions(-) create mode 100644 packages/nitrogen/src/views/createHostComponentJs.ts create mode 100644 packages/react-native-nitro-image/nitrogen/generated/shared/json/TestViewConfig.json create mode 100644 packages/react-native-nitro-image/src/views/TestView.ts diff --git a/packages/nitrogen/src/views/CppHybridViewComponent.ts b/packages/nitrogen/src/views/CppHybridViewComponent.ts index 616277afd..8cd2f8dbb 100644 --- a/packages/nitrogen/src/views/CppHybridViewComponent.ts +++ b/packages/nitrogen/src/views/CppHybridViewComponent.ts @@ -5,6 +5,7 @@ import { createFileMetadataString, escapeCppName } from '../syntax/helpers.js' import { NitroConfig } from '../config/NitroConfig.js' import { getHybridObjectName } from '../syntax/getHybridObjectName.js' import { includeHeader } from '../syntax/c++/includeNitroHeader.js' +import { createHostComponentJs } from './createHostComponentJs.js' interface ViewComponentNames { propsClassName: `${string}Props` @@ -232,7 +233,7 @@ namespace ${namespace} { #endif `.trim() - return [ + const files: SourceFile[] = [ { name: `${component}.hpp`, content: componentHeaderCode, @@ -248,4 +249,7 @@ namespace ${namespace} { subdirectory: ['views'], }, ] + const jsFiles = createHostComponentJs(spec) + files.push(...(jsFiles as unknown as SourceFile[])) + return files } diff --git a/packages/nitrogen/src/views/createHostComponentJs.ts b/packages/nitrogen/src/views/createHostComponentJs.ts new file mode 100644 index 000000000..e457bf458 --- /dev/null +++ b/packages/nitrogen/src/views/createHostComponentJs.ts @@ -0,0 +1,32 @@ +import type { Language } from '../getPlatformSpecs.js' +import type { HybridObjectSpec } from '../syntax/HybridObjectSpec.js' +import type { SourceFile } from '../syntax/SourceFile.js' +import { getHybridObjectName } from '../syntax/getHybridObjectName.js' +import { indent } from '../utils.js' + +export function createHostComponentJs(spec: HybridObjectSpec): SourceFile[] { + const { T } = getHybridObjectName(spec.name) + const props = spec.properties.map((p) => `"${p.name}": true`) + + const code = ` +{ + "uiViewClassName": "${T}", + "supportsRawText": false, + "bubblingEventTypes": {}, + "directEventTypes": {}, + "validAttributes": { + ${indent(props.join(',\n'), ' ')} + } +} + `.trim() + + return [ + { + content: code, + language: 'json' as Language, + name: `${T}Config.json`, + platform: 'shared', + subdirectory: [], + }, + ] +} diff --git a/packages/react-native-nitro-image/nitrogen/generated/ios/c++/views/HybridTestViewComponent.mm b/packages/react-native-nitro-image/nitrogen/generated/ios/c++/views/HybridTestViewComponent.mm index 63a0a45f2..1f857f3dd 100644 --- a/packages/react-native-nitro-image/nitrogen/generated/ios/c++/views/HybridTestViewComponent.mm +++ b/packages/react-native-nitro-image/nitrogen/generated/ios/c++/views/HybridTestViewComponent.mm @@ -53,9 +53,11 @@ - (instancetype) init { - (void) updateView { // 1. Get Swift part NitroImage::HybridTestViewSpec_cxx& swiftPart = _hybridView->getSwiftPart(); + // 2. Get UIView* void* viewUnsafe = swiftPart.getView(); UIView* view = (__bridge_transfer UIView*) viewUnsafe; + // 3. Update RCTViewComponentView's [contentView] [self setContentView:view]; } diff --git a/packages/react-native-nitro-image/nitrogen/generated/shared/json/TestViewConfig.json b/packages/react-native-nitro-image/nitrogen/generated/shared/json/TestViewConfig.json new file mode 100644 index 000000000..0ea609aa1 --- /dev/null +++ b/packages/react-native-nitro-image/nitrogen/generated/shared/json/TestViewConfig.json @@ -0,0 +1,10 @@ +{ + "uiViewClassName": "TestView", + "supportsRawText": false, + "bubblingEventTypes": {}, + "directEventTypes": {}, + "validAttributes": { + "someProp": true, + "someCallback": true + } +} diff --git a/packages/react-native-nitro-image/src/views/TestView.ts b/packages/react-native-nitro-image/src/views/TestView.ts new file mode 100644 index 000000000..0d533373d --- /dev/null +++ b/packages/react-native-nitro-image/src/views/TestView.ts @@ -0,0 +1,7 @@ +import { getHostComponent } from 'react-native-nitro-modules' +import TestViewConfig from '../../nitrogen/generated/shared/json/TestViewConfig.json' + +/** + * Represents the HybridView `TestView`, which can be rendered as a React Native view. + */ +export const TestView = getHostComponent('TestView', () => TestViewConfig) diff --git a/packages/react-native-nitro-modules/src/views/getHostComponent.ts b/packages/react-native-nitro-modules/src/views/getHostComponent.ts index 80aa702c3..be2b45442 100644 --- a/packages/react-native-nitro-modules/src/views/getHostComponent.ts +++ b/packages/react-native-nitro-modules/src/views/getHostComponent.ts @@ -1,13 +1,13 @@ -import type { HostComponent } from 'react-native' +import { Platform, type HostComponent } from 'react-native' // @ts-expect-error this unfortunately isn't typed or default-exported. import * as NativeComponentRegistry from 'react-native/Libraries/NativeComponent/NativeComponentRegistry' -interface ViewConfig { +export interface ViewConfig { uiViewClassName: string supportsRawText?: boolean bubblingEventTypes: Record directEventTypes: Record - validAttributes: Record + validAttributes: Record } /** @@ -17,5 +17,10 @@ export function getHostComponent( name: string, getViewConfig: () => ViewConfig ): HostComponent { + if (NativeComponentRegistry == null) { + throw new Error( + `NativeComponentRegistry is not available on ${Platform.OS}!` + ) + } return NativeComponentRegistry.get(name, getViewConfig) }