Skip to content

Commit

Permalink
Add a simple fabric component example
Browse files Browse the repository at this point in the history
Summary:
This diff adds a very simple example to show the use of new architecture in a component.

Changelog: [internal]

Reviewed By: cortinico

Differential Revision: D32045059

fbshipit-source-id: f388bfb765241122de425fbef61cea0620cd31ac
  • Loading branch information
sota000 authored and facebook-github-bot committed Nov 18, 2021
1 parent 85ce4ef commit d29f3d2
Show file tree
Hide file tree
Showing 6 changed files with 299 additions and 0 deletions.
47 changes: 47 additions & 0 deletions packages/rn-tester/NativeComponentExample/MyNativeView.podspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Copyright (c) Facebook, Inc. and its affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.

require "json"

package = JSON.parse(File.read(File.join(__dir__, "../" "package.json")))

folly_compiler_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -Wno-comma -Wno-shorten-64-to-32'
folly_version = '2021.06.28.00-v2'
boost_version = '1.76.0'
boost_compiler_flags = '-Wno-documentation'

Pod::Spec.new do |s|
s.name = "MyNativeView"
s.version = package["version"]
s.summary = package["description"]
s.description = "my-native-view"
s.homepage = "https://github.com/sota000/my-native-view.git"
s.license = "MIT"
s.platforms = { :ios => "11.0", :tvos => "11.0" }
s.compiler_flags = folly_compiler_flags + ' ' + boost_compiler_flags + ' -Wno-nullability-completeness'
s.author = "Facebook, Inc. and its affiliates"
s.source = { :git => "https://github.com/facebook/my-native-view.git", :tag => "#{s.version}" }
s.pod_target_xcconfig = {
"HEADER_SEARCH_PATHS" => "\"$(PODS_ROOT)/boost\" \"$(PODS_ROOT)/RCT-Folly\" \"$(PODS_ROOT)/boost\""
}

s.source_files = "ios/**/*.{h,m,mm,cpp}"
s.requires_arc = true

s.dependency "React"
s.dependency "React-RCTFabric"
s.dependency "React-Codegen"
s.dependency "RCTRequired"
s.dependency "RCTTypeSafety"
s.dependency "ReactCommon/turbomodule/core"

# Enable codegen for this library
use_react_native_codegen!(s, {
:library_name => "MyNativeViewSpec",
:react_native_path => "../../../",
:js_srcs_dir => "./js",
:library_type => "components"
})
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

#import <UIKit/UIKit.h>
#import <React/RCTViewComponentView.h>

NS_ASSUME_NONNULL_BEGIN

@interface RNTMyNativeViewComponentView : RCTViewComponentView

- (UIColor *)UIColorFromHexString: (const std::string)hexString;

@end

NS_ASSUME_NONNULL_END
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

#import "RNTMyNativeViewComponentView.h"

#import <react/renderer/components/MyNativeViewSpec/ComponentDescriptors.h>
#import <react/renderer/components/MyNativeViewSpec/Props.h>
#import <react/renderer/components/MyNativeViewSpec/EventEmitters.h>
#import <react/renderer/components/MyNativeViewSpec/RCTComponentViewHelpers.h>

#import "RCTFabricComponentsPlugins.h"

using namespace facebook::react;

@interface RNTMyNativeViewComponentView () <RCTRNTMyNativeViewViewProtocol>
@end

@implementation RNTMyNativeViewComponentView {
UIView *_view;
}

+ (ComponentDescriptorProvider)componentDescriptorProvider
{
return concreteComponentDescriptorProvider<RNTMyNativeViewComponentDescriptor>();
}

- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
static const auto defaultProps = std::make_shared<const RNTMyNativeViewProps>();
_props = defaultProps;

_view = [[UIView alloc] init];
_view.backgroundColor = [UIColor redColor];

self.contentView = _view;
}

return self;
}

- (UIColor *)UIColorFromHexString:(const std::string)hexString {
unsigned rgbValue = 0;
NSString *colorString = [NSString stringWithCString:hexString.c_str()
encoding:[NSString defaultCStringEncoding]];
NSScanner *scanner = [NSScanner scannerWithString:colorString];
[scanner setScanLocation:1]; // bypass '#' character
[scanner scanHexInt:&rgbValue];
return [UIColor colorWithRed:((rgbValue & 0xFF0000) >> 16)/255.0 green:((rgbValue & 0xFF00) >> 8)/255.0 blue:(rgbValue & 0xFF)/255.0 alpha:1.0];
}

- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
{
[super updateProps:props oldProps:oldProps];
}

- (void)onChange:(UIView *)sender
{
// No-op
// std::dynamic_pointer_cast<const ViewEventEmitter>(_eventEmitter)
// ->onChange(ViewEventEmitter::OnChange{.value = static_cast<bool>(sender.on)});
}

#pragma mark - Native Commands

- (void)handleCommand:(const NSString *)commandName args:(const NSArray *)args
{
RCTRNTMyNativeViewHandleCommand(self, commandName, args);
}

- (void)callNativeMethodToChangeBackgroundColor:(NSString *)colorString
{
UIColor *color = [self UIColorFromHexString:std::string([colorString UTF8String])];
_view.backgroundColor = color;
}
@end

Class<RCTComponentViewProtocol> RNTMyNativeViewCls(void)
{
return RNTMyNativeViewComponentView.class;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

#import <React/RCTViewManager.h>
#import <React/RCTUIManager.h>
#import <React/RCTLog.h>

@interface RNTMyNativeViewManager : RCTViewManager
@end

@implementation RNTMyNativeViewManager

RCT_EXPORT_MODULE(RNTMyNativeView)

RCT_EXPORT_VIEW_PROPERTY(backgroundColor, UIColor)

RCT_EXPORT_METHOD(callNativeMethodToChangeBackgroundColor:(nonnull NSNumber *)reactTag
color:(NSString *)color
) {
[self.bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, NSDictionary<NSNumber *,UIView *> *viewRegistry) {
UIView *view = viewRegistry[reactTag];
if (!view || ![view isKindOfClass:[UIView class]]) {
RCTLogError(@"Cannot find NativeView with tag #%@", reactTag);
return;
}

unsigned rgbValue = 0;
NSString *colorString = [NSString stringWithCString:std::string([color UTF8String]).c_str()
encoding:[NSString defaultCStringEncoding]];
NSScanner *scanner = [NSScanner scannerWithString:colorString];
[scanner setScanLocation:1]; // bypass '#' character
[scanner scanHexInt:&rgbValue];

view.backgroundColor = [UIColor colorWithRed:((rgbValue & 0xFF0000) >> 16)/255.0 green:((rgbValue & 0xFF00) >> 8)/255.0 blue:(rgbValue & 0xFF)/255.0 alpha:1.0];
}];

}

- (UIView *)view
{
return [[UIView alloc] init];
}

@end
62 changes: 62 additions & 0 deletions packages/rn-tester/NativeComponentExample/js/MyNativeView.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
*/

import * as React from 'react';
import {useRef, useState} from 'react';
import {View, Button} from 'react-native';
import RNTMyNativeView, {
Commands as RNTMyNativeViewCommands,
} from './MyNativeViewNativeComponent';
import type {MyNativeViewType} from './MyNativeViewNativeComponent';

const colors = [
'#0000FF',
'#FF0000',
'#00FF00',
'#003300',
'#330000',
'#000033',
];

// This is an example component that migrates to use the new architecture.
export default function MyNativeView(props: {}): React.Node {
const ref = useRef<React.ElementRef<MyNativeViewType> | null>(null);
const [opacity, setOpacity] = useState(1.0);
return (
<View style={{flex: 1}}>
<RNTMyNativeView ref={ref} style={{flex: 1}} opacity={opacity} />
<Button
title="Change Background"
onPress={() => {
if (ref.current) {
RNTMyNativeViewCommands.callNativeMethodToChangeBackgroundColor(
ref.current,
colors[Math.floor(Math.random() * 5)],
);
}
}}
/>
<Button
title="Set Opacity"
onPress={() => {
setOpacity(Math.random());
}}
/>
<Button
title="Console.log Measure"
onPress={() => {
ref.current?.measure((x, y, width, height) => {
console.log(x, y, width, height);
});
}}
/>
</View>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
*/

import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';
import codegenNativeCommands from 'react-native/Libraries/Utilities/codegenNativeCommands';
import type {HostComponent} from 'react-native/Libraries/Renderer/shims/ReactNativeTypes';
import type {ViewProps} from 'react-native/Libraries/Components/View/ViewPropTypes';
import type {Float} from 'react-native/Libraries/Types/CodegenTypes';
import * as React from 'react';

type NativeProps = $ReadOnly<{|
...ViewProps,
opacity?: Float,
|}>;

export type MyNativeViewType = HostComponent<NativeProps>;

interface NativeCommands {
+callNativeMethodToChangeBackgroundColor: (
viewRef: React.ElementRef<MyNativeViewType>,
color: string,
) => void;
}

export const Commands: NativeCommands = codegenNativeCommands<NativeCommands>({
supportedCommands: ['callNativeMethodToChangeBackgroundColor'],
});

export default (codegenNativeComponent<NativeProps>(
'RNTMyNativeView',
): MyNativeViewType);

0 comments on commit d29f3d2

Please sign in to comment.