Skip to content

Commit

Permalink
feat(react-native-masked-view#162): fabric support
Browse files Browse the repository at this point in the history
- add JS Flow spec
- make android viewmanager to conform to codegen-ed specs
- add codegen-ed spec to make viewmanager work also in old arch
- use install_module_dependencies in the podspec to install deps on both new and old architectures
- add subclass of RCTViewComponentView
- use fabric implementation when RCT_NEW_ARCH_ENABLED flag is true
- set RN peerDependency to be version >= 0.71
  • Loading branch information
mateusz1913 committed Mar 24, 2024
1 parent 40ff01d commit 8843834
Show file tree
Hide file tree
Showing 12 changed files with 221 additions and 31 deletions.
4 changes: 2 additions & 2 deletions RNCMaskedView.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ Pod::Spec.new do |s|
s.platforms = { :ios => "9.0", :tvos => "9.0" }

s.source = { :git => "https://github.com/react-native-masked-view/masked-view.git", :tag => "v#{s.version}" }
s.source_files = "ios/**/*.{h,m}"
s.source_files = "ios/**/*.{h,m,mm}"

s.dependency 'React-Core'
install_modules_dependencies(s)
end
20 changes: 16 additions & 4 deletions android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,14 @@ buildscript {
}
}

def isNewArchitectureEnabled() {
return project.hasProperty("newArchEnabled") && project.newArchEnabled == "true"
}

apply plugin: 'com.android.library'
if (isNewArchitectureEnabled()) {
apply plugin: "com.facebook.react"
}

def agpVersion = com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION.tokenize('.')[0].toInteger()
def shouldUseNameSpace = agpVersion >= 7
Expand All @@ -39,20 +46,25 @@ manifestContent.replaceAll(" ", " ")
manifestOutFile.write(manifestContent)

android {
compileSdkVersion safeExtGet('compileSdkVersion', 28)
compileSdkVersion safeExtGet('compileSdkVersion', 33)

if(shouldUseNameSpace){
namespace = "org.reactnative.maskedview"
}

defaultConfig {
minSdkVersion safeExtGet('minSdkVersion', 16)
targetSdkVersion safeExtGet('targetSdkVersion', 28)
minSdkVersion safeExtGet('minSdkVersion', 21)
targetSdkVersion safeExtGet('targetSdkVersion', 33)
buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
}

sourceSets {
main {
java.srcDirs = ['src/main/java']
if (isNewArchitectureEnabled()) {
java.srcDirs += ['src/newarch/java', "${project.buildDir}/generated/source/codegen/java"]
} else {
java.srcDirs += ['src/oldarch/java']
}
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,34 +1,40 @@
package org.reactnative.maskedview;

import android.view.View;
import android.widget.Toast;
import androidx.annotation.Nullable;

import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.common.MapBuilder;
import com.facebook.react.uimanager.SimpleViewManager;
import com.facebook.react.uimanager.ThemedReactContext;
import com.facebook.react.uimanager.ViewGroupManager;
import com.facebook.react.uimanager.ViewManagerDelegate;
import com.facebook.react.uimanager.annotations.ReactProp;
import com.facebook.react.viewmanagers.RNCMaskedViewManagerDelegate;
import com.facebook.react.viewmanagers.RNCMaskedViewManagerInterface;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class RNCMaskedViewManager extends ViewGroupManager<RNCMaskedView> implements RNCMaskedViewManagerInterface<RNCMaskedView> {
private final ViewManagerDelegate<RNCMaskedView> mDelegate;

public class RNCMaskedViewManager extends ViewGroupManager<RNCMaskedView> {
private static final String REACT_CLASS = "RNCMaskedView";

public RNCMaskedViewManager() {
mDelegate = new RNCMaskedViewManagerDelegate<>(this);
}

@Override
public String getName() {
return REACT_CLASS;
}

@Override
public ViewManagerDelegate<RNCMaskedView> getDelegate() {
return mDelegate;
}

@Override
protected RNCMaskedView createViewInstance(ThemedReactContext themedReactContext) {
return new RNCMaskedView(themedReactContext);
}

@Override
@ReactProp(name = "androidRenderingMode")
public void setAndroidRenderingMode(RNCMaskedView view, @Nullable String renderingMode) {
if (renderingMode != null) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,25 +1,41 @@
package org.reactnative.maskedview;

import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.JavaScriptModule;
import androidx.annotation.Nullable;

import com.facebook.react.TurboReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.module.model.ReactModuleInfo;
import com.facebook.react.module.model.ReactModuleInfoProvider;
import com.facebook.react.uimanager.ViewManager;

import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class RNCMaskedViewPackage extends TurboReactPackage {
@Override
@Nullable
public NativeModule getModule(String name, ReactApplicationContext reactContext) {
return null;
}

public class RNCMaskedViewPackage implements ReactPackage {
@Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactApplicationContext) {
return Collections.emptyList();
public ReactModuleInfoProvider getReactModuleInfoProvider() {
final Map<String, ReactModuleInfo> reactModuleInfoMap = new HashMap<>();
return new ReactModuleInfoProvider() {
@Override
public Map<String, ReactModuleInfo> getReactModuleInfos() {
return reactModuleInfoMap;
}
};
}

@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactApplicationContext) {
return Arrays.<ViewManager>asList(
new RNCMaskedViewManager()
);
return Arrays.<ViewManager>asList(
new RNCMaskedViewManager()
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/**
* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen).
*
* Do not edit this file as changes may cause incorrect behavior and will be lost
* once the code is regenerated.
*
* @generated by codegen project: GeneratePropsJavaDelegate.js
*/

package com.facebook.react.viewmanagers;

import android.view.View;
import androidx.annotation.Nullable;
import com.facebook.react.uimanager.BaseViewManagerDelegate;
import com.facebook.react.uimanager.BaseViewManagerInterface;

public class RNCMaskedViewManagerDelegate<T extends View, U extends BaseViewManagerInterface<T> & RNCMaskedViewManagerInterface<T>> extends BaseViewManagerDelegate<T, U> {
public RNCMaskedViewManagerDelegate(U viewManager) {
super(viewManager);
}
@Override
public void setProperty(T view, String propName, @Nullable Object value) {
switch (propName) {
case "androidRenderingMode":
mViewManager.setAndroidRenderingMode(view, (String) value);
break;
default:
super.setProperty(view, propName, value);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/**
* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen).
*
* Do not edit this file as changes may cause incorrect behavior and will be lost
* once the code is regenerated.
*
* @generated by codegen project: GeneratePropsJavaInterface.js
*/

package com.facebook.react.viewmanagers;

import android.view.View;
import androidx.annotation.Nullable;

public interface RNCMaskedViewManagerInterface<T extends View> {
void setAndroidRenderingMode(T view, @Nullable String value);
}
7 changes: 7 additions & 0 deletions ios/RNCMaskedViewComponentView.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#if RCT_NEW_ARCH_ENABLED
#import <React/RCTViewComponentView.h>

@interface RNCMaskedViewComponentView : RCTViewComponentView

@end
#endif
66 changes: 66 additions & 0 deletions ios/RNCMaskedViewComponentView.mm
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#if RCT_NEW_ARCH_ENABLED
#import "RNCMaskedViewComponentView.h"

#import <React/RCTConversions.h>
#import <RCTTypeSafety/RCTConvertHelpers.h>

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

#import "RCTFabricComponentsPlugins.h"

using namespace facebook::react;

@interface RNCMaskedViewComponentView () <RCTRNCMaskedViewViewProtocol>
@end

@implementation RNCMaskedViewComponentView

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

- (void)mountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView index:(NSInteger)index
{
if (index == 0) {
self.maskView = childComponentView;
return;
}
[self addSubview:childComponentView];
}

- (void)unmountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView index:(NSInteger)index
{
if (index == 0) {
self.maskView = nil;
return;
}
[childComponentView removeFromSuperview];
}

- (void)invalidateLayer
{
// RCTViewComponentView uses invalidateLayer to do border rendering.
// We don't need to do that in RNCMaskedViewComponentView, so we
// stub this method and override the default implementation.
}

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

@end

Class<RCTComponentViewProtocol> RNCMaskedViewCls(void)
{
return RNCMaskedViewComponentView.class;
}
#endif
6 changes: 6 additions & 0 deletions ios/RNCMaskedViewManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,21 @@

#import "RNCMaskedViewManager.h"

#if RCT_NEW_ARCH_ENABLED
#else
#import "RNCMaskedView.h"
#endif

@implementation RNCMaskedViewManager

RCT_EXPORT_MODULE()

#if RCT_NEW_ARCH_ENABLED
#else
- (UIView *)view
{
return [RNCMaskedView new];
}
#endif

@end
9 changes: 4 additions & 5 deletions js/MaskedView.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,9 @@
*/

import * as React from 'react';
import { View, StyleSheet, requireNativeComponent } from 'react-native';

const RNCMaskedView = requireNativeComponent<any>('RNCMaskedView');
import { View, StyleSheet } from 'react-native';

import RNCMaskedViewNativeComponent from './RNCMaskedViewNativeComponent';
import type { MaskedViewProps } from './MaskedViewTypes';

/**
Expand Down Expand Up @@ -70,12 +69,12 @@ export default class MaskedView extends React.Component<MaskedViewProps> {
}

return (
<RNCMaskedView {...otherViewProps}>
<RNCMaskedViewNativeComponent {...otherViewProps}>
<View pointerEvents="none" style={StyleSheet.absoluteFill}>
{maskElement}
</View>
{children}
</RNCMaskedView>
</RNCMaskedViewNativeComponent>
);
}
}
22 changes: 22 additions & 0 deletions js/RNCMaskedViewNativeComponent.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/**
* @flow strict-local
* @format
*/

import type {ViewProps} from 'react-native/Libraries/Components/View/ViewPropTypes';
import type {HostComponent} from 'react-native/Libraries/Renderer/shims/ReactNativeTypes';
import type {WithDefault} from 'react-native/Libraries/Types/CodegenTypes';

import * as React from 'react';
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';

type NativeProps = $ReadOnly<{
...ViewProps,

//Props
androidRenderingMode?: WithDefault<'hardware' | 'software', 'hardware'>,
}>;

export default (codegenNativeComponent<NativeProps>(
'RNCMaskedView',
): HostComponent<NativeProps>);
12 changes: 10 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@
"test:prettier": "prettier --check './**/*.js'"
},
"peerDependencies": {
"react": ">=16",
"react-native": ">=0.57"
"react": ">=18",
"react-native": ">=0.71"
},
"files": [
"index.js",
Expand Down Expand Up @@ -52,5 +52,13 @@
},
"publishConfig": {
"access": "public"
},
"codegenConfig": {
"name": "RNMaskedViewSpec",
"type": "components",
"jsSrcsDir": "js",
"android": {
"javaPackageName": "org.reactnative.maskedview"
}
}
}

0 comments on commit 8843834

Please sign in to comment.