mirror of
https://github.com/zoriya/react-native-svg.git
synced 2025-12-06 07:06:11 +00:00
feat: add FeMerge and FeMergeNode filters (#2369)
# Summary As mentioned in #2362 Introduce new filters: * `FeMerge` * `FeMergeNode` ## Example usage ```tsx <Svg width="200" height="200"> <Filter id="mergeWithOffset" width="180" height="180"> <FeOffset dx="50" dy="50" result="test" /> <FeOffset dx="100" dy="100" in="SourceGraphic" /> <FeMerge> <FeMergeNode in="SourceGraphic" /> <FeMergeNode in="test" /> <FeMergeNode /> </FeMerge> </Filter> <Rect x="0" y="0" width="100" height="100" stroke="black" fill="red" filter="url(#mergeWithOffset)" /> </Svg> ``` <img width="207" alt="image" src="https://github.com/user-attachments/assets/9cb3ded6-f939-4b2b-8ece-df54e64fe898"> ## Test Plan `Example` app -> `Filters` -> `FeMerge` ## Compatibility | OS | Implemented | | ------- | :---------: | | iOS | ✅ | | Android | ✅ | ## Checklist - [x] I have tested this on a device and a simulator - [x] I added documentation in `README.md` - [x] I updated the typed files (typescript)
This commit is contained in:
1
USAGE.md
1
USAGE.md
@@ -1261,6 +1261,7 @@ Currently supported\* filters are:
|
||||
|
||||
- FeColorMatrix
|
||||
- FeGaussianBlur
|
||||
- FeMerge
|
||||
- FeOffset
|
||||
|
||||
\*_More filters are coming soon_
|
||||
|
||||
43
android/src/main/java/com/horcrux/svg/FeMergeView.java
Normal file
43
android/src/main/java/com/horcrux/svg/FeMergeView.java
Normal file
@@ -0,0 +1,43 @@
|
||||
package com.horcrux.svg;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import com.facebook.react.bridge.ReactContext;
|
||||
import com.facebook.react.bridge.ReadableArray;
|
||||
import com.facebook.react.bridge.ReadableType;
|
||||
import java.util.HashMap;
|
||||
|
||||
@SuppressLint("ViewConstructor")
|
||||
class FeMergeView extends FilterPrimitiveView {
|
||||
private ReadableArray mNodes;
|
||||
|
||||
public FeMergeView(ReactContext reactContext) {
|
||||
super(reactContext);
|
||||
}
|
||||
|
||||
public void setNodes(ReadableArray nodes) {
|
||||
this.mNodes = nodes;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bitmap applyFilter(HashMap<String, Bitmap> resultsMap, Bitmap prevResult) {
|
||||
Bitmap result =
|
||||
Bitmap.createBitmap(prevResult.getWidth(), prevResult.getHeight(), Bitmap.Config.ARGB_8888);
|
||||
Canvas canvas = new Canvas(result);
|
||||
int nodesSize = this.mNodes.size();
|
||||
for (int i = 0; i < nodesSize; i++) {
|
||||
Bitmap sourceFromResults =
|
||||
this.mNodes.getType(i) == ReadableType.String
|
||||
? resultsMap.get(this.mNodes.getString(i))
|
||||
: prevResult;
|
||||
if (sourceFromResults != null) {
|
||||
canvas.drawBitmap(sourceFromResults, 0, 0, new Paint());
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -107,6 +107,8 @@ import com.facebook.react.viewmanagers.RNSVGFeColorMatrixManagerDelegate;
|
||||
import com.facebook.react.viewmanagers.RNSVGFeColorMatrixManagerInterface;
|
||||
import com.facebook.react.viewmanagers.RNSVGFeGaussianBlurManagerDelegate;
|
||||
import com.facebook.react.viewmanagers.RNSVGFeGaussianBlurManagerInterface;
|
||||
import com.facebook.react.viewmanagers.RNSVGFeMergeManagerDelegate;
|
||||
import com.facebook.react.viewmanagers.RNSVGFeMergeManagerInterface;
|
||||
import com.facebook.react.viewmanagers.RNSVGFeOffsetManagerDelegate;
|
||||
import com.facebook.react.viewmanagers.RNSVGFeOffsetManagerInterface;
|
||||
import com.facebook.react.viewmanagers.RNSVGFilterManagerDelegate;
|
||||
@@ -589,6 +591,7 @@ class VirtualViewManager<V extends VirtualView> extends ViewGroupManager<Virtual
|
||||
RNSVGFilter,
|
||||
RNSVGFeColorMatrix,
|
||||
RNSVGFeGaussianBlur,
|
||||
RNSVGFeMerge,
|
||||
RNSVGFeOffset,
|
||||
RNSVGMarker,
|
||||
RNSVGForeignObject,
|
||||
@@ -640,6 +643,8 @@ class VirtualViewManager<V extends VirtualView> extends ViewGroupManager<Virtual
|
||||
return new FeColorMatrixView(reactContext);
|
||||
case RNSVGFeGaussianBlur:
|
||||
return new FeGaussianBlurView(reactContext);
|
||||
case RNSVGFeMerge:
|
||||
return new FeMergeView(reactContext);
|
||||
case RNSVGFeOffset:
|
||||
return new FeOffsetView(reactContext);
|
||||
case RNSVGMarker:
|
||||
@@ -1630,6 +1635,21 @@ class RenderableViewManager<T extends RenderableView> extends VirtualViewManager
|
||||
}
|
||||
}
|
||||
|
||||
static class FeMergeManager extends FilterPrimitiveManager<FeMergeView>
|
||||
implements RNSVGFeMergeManagerInterface<FeMergeView> {
|
||||
FeMergeManager() {
|
||||
super(SVGClass.RNSVGFeMerge);
|
||||
mDelegate = new RNSVGFeMergeManagerDelegate(this);
|
||||
}
|
||||
|
||||
public static final String REACT_CLASS = "RNSVGFeMerge";
|
||||
|
||||
@ReactProp(name = "nodes")
|
||||
public void setNodes(FeMergeView node, ReadableArray nodes) {
|
||||
node.setNodes(nodes);
|
||||
}
|
||||
}
|
||||
|
||||
static class FeOffsetManager extends FilterPrimitiveManager<FeOffsetView>
|
||||
implements RNSVGFeOffsetManagerInterface<FeOffsetView> {
|
||||
FeOffsetManager() {
|
||||
|
||||
@@ -232,6 +232,15 @@ public class SvgPackage extends TurboReactPackage implements ViewManagerOnDemand
|
||||
return new FeGaussianBlurManager();
|
||||
}
|
||||
}));
|
||||
specs.put(
|
||||
FeMergeManager.REACT_CLASS,
|
||||
ModuleSpec.viewManagerSpec(
|
||||
new Provider<NativeModule>() {
|
||||
@Override
|
||||
public NativeModule get() {
|
||||
return new FeMergeManager();
|
||||
}
|
||||
}));
|
||||
specs.put(
|
||||
FeOffsetManager.REACT_CLASS,
|
||||
ModuleSpec.viewManagerSpec(
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* 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.bridge.DynamicFromObject;
|
||||
import com.facebook.react.bridge.ReadableArray;
|
||||
import com.facebook.react.uimanager.BaseViewManagerDelegate;
|
||||
import com.facebook.react.uimanager.BaseViewManagerInterface;
|
||||
|
||||
public class RNSVGFeMergeManagerDelegate<T extends View, U extends BaseViewManagerInterface<T> & RNSVGFeMergeManagerInterface<T>> extends BaseViewManagerDelegate<T, U> {
|
||||
public RNSVGFeMergeManagerDelegate(U viewManager) {
|
||||
super(viewManager);
|
||||
}
|
||||
@Override
|
||||
public void setProperty(T view, String propName, @Nullable Object value) {
|
||||
switch (propName) {
|
||||
case "x":
|
||||
mViewManager.setX(view, new DynamicFromObject(value));
|
||||
break;
|
||||
case "y":
|
||||
mViewManager.setY(view, new DynamicFromObject(value));
|
||||
break;
|
||||
case "width":
|
||||
mViewManager.setWidth(view, new DynamicFromObject(value));
|
||||
break;
|
||||
case "height":
|
||||
mViewManager.setHeight(view, new DynamicFromObject(value));
|
||||
break;
|
||||
case "result":
|
||||
mViewManager.setResult(view, value == null ? null : (String) value);
|
||||
break;
|
||||
case "nodes":
|
||||
mViewManager.setNodes(view, (ReadableArray) value);
|
||||
break;
|
||||
default:
|
||||
super.setProperty(view, propName, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* 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;
|
||||
import com.facebook.react.bridge.Dynamic;
|
||||
import com.facebook.react.bridge.ReadableArray;
|
||||
|
||||
public interface RNSVGFeMergeManagerInterface<T extends View> {
|
||||
void setX(T view, Dynamic value);
|
||||
void setY(T view, Dynamic value);
|
||||
void setWidth(T view, Dynamic value);
|
||||
void setHeight(T view, Dynamic value);
|
||||
void setResult(T view, @Nullable String value);
|
||||
void setNodes(T view, @Nullable ReadableArray value);
|
||||
}
|
||||
7
apple/Filters/RNSVGFeMerge.h
Normal file
7
apple/Filters/RNSVGFeMerge.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#import "RNSVGFilterPrimitive.h"
|
||||
|
||||
@interface RNSVGFeMerge : RNSVGFilterPrimitive
|
||||
|
||||
@property (nonatomic, copy) NSArray<NSString *> *nodes;
|
||||
|
||||
@end
|
||||
105
apple/Filters/RNSVGFeMerge.mm
Normal file
105
apple/Filters/RNSVGFeMerge.mm
Normal file
@@ -0,0 +1,105 @@
|
||||
#import "RNSVGFeMerge.h"
|
||||
|
||||
#ifdef RCT_NEW_ARCH_ENABLED
|
||||
#import <React/RCTConversions.h>
|
||||
#import <React/RCTFabricComponentsPlugins.h>
|
||||
#import <react/renderer/components/rnsvg/ComponentDescriptors.h>
|
||||
#import <react/renderer/components/view/conversions.h>
|
||||
#import "RNSVGFabricConversions.h"
|
||||
#endif // RCT_NEW_ARCH_ENABLED
|
||||
|
||||
@implementation RNSVGFeMerge
|
||||
|
||||
#ifdef RCT_NEW_ARCH_ENABLED
|
||||
using namespace facebook::react;
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame
|
||||
{
|
||||
if (self = [super initWithFrame:frame]) {
|
||||
static const auto defaultProps = std::make_shared<const RNSVGFeMergeProps>();
|
||||
_props = defaultProps;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - RCTComponentViewProtocol
|
||||
|
||||
+ (ComponentDescriptorProvider)componentDescriptorProvider
|
||||
{
|
||||
return concreteComponentDescriptorProvider<RNSVGFeMergeComponentDescriptor>();
|
||||
}
|
||||
|
||||
- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
|
||||
{
|
||||
const auto &newProps = static_cast<const RNSVGFeMergeProps &>(*props);
|
||||
|
||||
if (newProps.nodes.size() > 0) {
|
||||
NSMutableArray *nodesArray = [NSMutableArray new];
|
||||
for (auto node : newProps.nodes) {
|
||||
id json = RNSVGConvertFollyDynamicToId(node);
|
||||
if ([json isKindOfClass:[NSString class]]) {
|
||||
[nodesArray addObject:[json stringValue]];
|
||||
} else {
|
||||
[nodesArray addObject:[NSNull null]];
|
||||
}
|
||||
}
|
||||
self.nodes = nodesArray;
|
||||
}
|
||||
|
||||
setCommonFilterProps(newProps, self);
|
||||
_props = std::static_pointer_cast<RNSVGFeMergeProps const>(props);
|
||||
}
|
||||
|
||||
- (void)prepareForRecycle
|
||||
{
|
||||
[super prepareForRecycle];
|
||||
_nodes = nil;
|
||||
}
|
||||
#endif // RCT_NEW_ARCH_ENABLED
|
||||
|
||||
- (void)setNodes:(NSArray<NSString *> *)nodes
|
||||
{
|
||||
if (nodes == _nodes) {
|
||||
return;
|
||||
}
|
||||
|
||||
_nodes = nodes;
|
||||
[self invalidate];
|
||||
}
|
||||
|
||||
- (CIImage *)applyFilter:(NSMutableDictionary<NSString *, CIImage *> *)results
|
||||
previousFilterResult:(CIImage *)previous
|
||||
ctm:(CGAffineTransform)ctm
|
||||
{
|
||||
CIFilter *filter = [CIFilter filterWithName:@"CISourceOverCompositing"];
|
||||
[filter setDefaults];
|
||||
|
||||
CIImage *result;
|
||||
|
||||
for (int i = 0; i < [self.nodes count]; i++) {
|
||||
NSString *nodeKey = [self.nodes objectAtIndex:i];
|
||||
CIImage *inputImage =
|
||||
[nodeKey isEqual:[NSNull null]] ? previous : [results objectForKey:[self.nodes objectAtIndex:i]];
|
||||
if (inputImage == nil) {
|
||||
continue;
|
||||
}
|
||||
if (result == nil) {
|
||||
result = inputImage;
|
||||
continue;
|
||||
}
|
||||
[filter setValue:result forKey:@"inputBackgroundImage"];
|
||||
[filter setValue:inputImage forKey:@"inputImage"];
|
||||
|
||||
result = [filter valueForKey:@"outputImage"];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef RCT_NEW_ARCH_ENABLED
|
||||
Class<RCTComponentViewProtocol> RNSVGFeMergeCls(void)
|
||||
{
|
||||
return RNSVGFeMerge.class;
|
||||
}
|
||||
#endif // RCT_NEW_ARCH_ENABLED
|
||||
|
||||
@end
|
||||
5
apple/ViewManagers/RNSVGFeMergeManager.h
Normal file
5
apple/ViewManagers/RNSVGFeMergeManager.h
Normal file
@@ -0,0 +1,5 @@
|
||||
#import "RNSVGFilterPrimitiveManager.h"
|
||||
|
||||
@interface RNSVGFeMergeManager : RNSVGFilterPrimitiveManager
|
||||
|
||||
@end
|
||||
15
apple/ViewManagers/RNSVGFeMergeManager.mm
Normal file
15
apple/ViewManagers/RNSVGFeMergeManager.mm
Normal file
@@ -0,0 +1,15 @@
|
||||
#import "RNSVGFeMergeManager.h"
|
||||
#import "RNSVGFeMerge.h"
|
||||
|
||||
@implementation RNSVGFeMergeManager
|
||||
|
||||
RCT_EXPORT_MODULE()
|
||||
|
||||
- (RNSVGFeMerge *)node
|
||||
{
|
||||
return [RNSVGFeMerge new];
|
||||
}
|
||||
|
||||
RCT_EXPORT_VIEW_PROPERTY(nodes, NSArray<NSString *>)
|
||||
|
||||
@end
|
||||
92
apps/examples/src/examples/Filters/FeMerge.tsx
Normal file
92
apps/examples/src/examples/Filters/FeMerge.tsx
Normal file
@@ -0,0 +1,92 @@
|
||||
import React, {Component} from 'react';
|
||||
import {
|
||||
Svg,
|
||||
Circle,
|
||||
FeColorMatrix,
|
||||
Filter,
|
||||
G,
|
||||
FeMerge,
|
||||
FeMergeNode,
|
||||
Rect,
|
||||
FeOffset,
|
||||
} from 'react-native-svg';
|
||||
|
||||
class WithOffsetsExample extends Component {
|
||||
static title = 'Merge with SourceGraphic and offsets';
|
||||
render() {
|
||||
return (
|
||||
<Svg width="200" height="200">
|
||||
<Filter id="mergeWithOffset" width="180" height="180">
|
||||
<FeOffset dx="50" dy="50" result="test" />
|
||||
<FeOffset dx="100" dy="100" in="SourceGraphic" />
|
||||
<FeMerge>
|
||||
<FeMergeNode in="SourceGraphic" />
|
||||
<FeMergeNode in="test" />
|
||||
<FeMergeNode />
|
||||
</FeMerge>
|
||||
</Filter>
|
||||
<Rect
|
||||
x="0"
|
||||
y="0"
|
||||
width="100"
|
||||
height="100"
|
||||
stroke="black"
|
||||
fill="red"
|
||||
filter="url(#mergeWithOffset)"
|
||||
/>
|
||||
</Svg>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class WithHueRotateExample extends Component {
|
||||
static title = 'Merge with SourceGraphic and HueRotate';
|
||||
render() {
|
||||
return (
|
||||
<Svg width="150" height="150">
|
||||
<Filter id="mergeWithHue" width="180" height="180">
|
||||
<FeOffset dx="50" dy="50" />
|
||||
<FeColorMatrix type="hueRotate" values="240" />
|
||||
<FeMerge>
|
||||
<FeMergeNode />
|
||||
<FeMergeNode in="SourceGraphic" />
|
||||
</FeMerge>
|
||||
</Filter>
|
||||
<Rect
|
||||
x="0"
|
||||
y="0"
|
||||
width="100"
|
||||
height="100"
|
||||
stroke="black"
|
||||
fill="red"
|
||||
filter="url(#mergeWithHue)"
|
||||
/>
|
||||
</Svg>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const icon = (
|
||||
<Svg height="30" width="30" viewBox="0 0 20 20">
|
||||
<Filter id="mergeWithOffsetIcon" width="180" height="180">
|
||||
<FeOffset dx="5" dy="5" />
|
||||
<FeMerge>
|
||||
<FeMergeNode />
|
||||
<FeMergeNode in="SourceGraphic" />
|
||||
</FeMerge>
|
||||
</Filter>
|
||||
<Rect
|
||||
x="1"
|
||||
y="1"
|
||||
width="13"
|
||||
height="13"
|
||||
fill="blue"
|
||||
filter="url(#mergeWithOffsetIcon)"
|
||||
strokeWidth="1"
|
||||
stroke="black"
|
||||
/>
|
||||
</Svg>
|
||||
);
|
||||
|
||||
const samples = [WithOffsetsExample, WithHueRotateExample];
|
||||
export {icon, samples};
|
||||
@@ -1,5 +1,12 @@
|
||||
import * as FeColorMatrix from './FeColorMatrix';
|
||||
import * as FeGaussianBlur from './FeGaussianBlur';
|
||||
import * as FeMerge from './FeMerge';
|
||||
import * as FeOffset from './FeOffset';
|
||||
import * as ReanimatedFeColorMatrix from './ReanimatedFeColorMatrix';
|
||||
export {FeColorMatrix, FeGaussianBlur, FeOffset, ReanimatedFeColorMatrix};
|
||||
export {
|
||||
FeColorMatrix,
|
||||
FeGaussianBlur,
|
||||
FeMerge,
|
||||
FeOffset,
|
||||
ReanimatedFeColorMatrix,
|
||||
};
|
||||
|
||||
@@ -19,6 +19,7 @@ module.exports = {
|
||||
'RNSVGDefsComponentDescriptor',
|
||||
'RNSVGFeColorMatrixComponentDescriptor',
|
||||
'RNSVGFeGaussianBlurComponentDescriptor',
|
||||
'RNSVGFeMergeComponentDescriptor',
|
||||
'RNSVGFeOffsetComponentDescriptor',
|
||||
'RNSVGFilterComponentDescriptor',
|
||||
'RNSVGEllipseComponentDescriptor',
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import Shape from './elements/Shape';
|
||||
|
||||
import {
|
||||
AstProps,
|
||||
camelCase,
|
||||
@@ -27,6 +26,7 @@ import {
|
||||
RNSVGEllipse,
|
||||
RNSVGFeColorMatrix,
|
||||
RNSVGFeGaussianBlur,
|
||||
RNSVGFeMerge,
|
||||
RNSVGFeOffset,
|
||||
RNSVGFilter,
|
||||
RNSVGForeignObject,
|
||||
@@ -65,6 +65,8 @@ export type { ClipPathProps } from './elements/ClipPath';
|
||||
export type { EllipseProps } from './elements/Ellipse';
|
||||
export type { FeColorMatrixProps } from './elements/filters/FeColorMatrix';
|
||||
export type { FeGaussianBlurProps } from './elements/filters/FeGaussianBlur';
|
||||
export type { FeMergeProps } from './elements/filters/FeMerge';
|
||||
export type { FeMergeNodeProps } from './elements/filters/FeMergeNode';
|
||||
export type { FeOffsetProps } from './elements/filters/FeOffset';
|
||||
export type { FilterProps } from './elements/filters/Filter';
|
||||
export type { FilterPrimitiveCommonProps } from './elements/filters/FilterPrimitive';
|
||||
@@ -101,6 +103,7 @@ export {
|
||||
RNSVGEllipse,
|
||||
RNSVGFeColorMatrix,
|
||||
RNSVGFeGaussianBlur,
|
||||
RNSVGFeMerge,
|
||||
RNSVGFeOffset,
|
||||
RNSVGFilter,
|
||||
RNSVGForeignObject,
|
||||
|
||||
@@ -24,6 +24,8 @@ import TextPath from './elements/TextPath';
|
||||
import Use from './elements/Use';
|
||||
import FeColorMatrix from './elements/filters/FeColorMatrix';
|
||||
import FeGaussianBlur from './elements/filters/FeGaussianBlur';
|
||||
import FeMerge from './elements/filters/FeMerge';
|
||||
import FeMergeNode from './elements/filters/FeMergeNode';
|
||||
import FeOffset from './elements/filters/FeOffset';
|
||||
import Filter from './elements/filters/Filter';
|
||||
|
||||
@@ -34,6 +36,8 @@ export {
|
||||
Ellipse,
|
||||
FeColorMatrix,
|
||||
FeGaussianBlur,
|
||||
FeMerge,
|
||||
FeMergeNode,
|
||||
FeOffset,
|
||||
Filter,
|
||||
ForeignObject,
|
||||
|
||||
@@ -3,6 +3,8 @@ import type { ClipPathProps } from './elements/ClipPath';
|
||||
import type { EllipseProps } from './elements/Ellipse';
|
||||
import type { FeColorMatrixProps } from './elements/filters/FeColorMatrix';
|
||||
import type { FeGaussianBlurProps } from './elements/filters/FeGaussianBlur';
|
||||
import type { FeMergeProps } from './elements/filters/FeMerge';
|
||||
import type { FeMergeNodeProps } from './elements/filters/FeMergeNode';
|
||||
import type { FeOffsetProps } from './elements/filters/FeOffset';
|
||||
import type { FilterProps } from './elements/filters/Filter';
|
||||
import type { ForeignObjectProps } from './elements/ForeignObject';
|
||||
@@ -53,6 +55,14 @@ export class FeGaussianBlur extends WebShape<BaseProps & FeGaussianBlurProps> {
|
||||
tag = 'feGaussianBlur' as const;
|
||||
}
|
||||
|
||||
export class FeMerge extends WebShape<BaseProps & FeMergeProps> {
|
||||
tag = 'feMerge' as const;
|
||||
}
|
||||
|
||||
export class FeMergeNode extends WebShape<BaseProps & FeMergeNodeProps> {
|
||||
tag = 'feMergeNode' as const;
|
||||
}
|
||||
|
||||
export class FeOffset extends WebShape<BaseProps & FeOffsetProps> {
|
||||
tag = 'feOffset' as const;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import RNSVGFeColorMatrix from '../../fabric/FeColorMatrixNativeComponent';
|
||||
import {
|
||||
extractFeColorMatrix,
|
||||
extractFilter,
|
||||
extractIn,
|
||||
} from '../../lib/extract/extractFilter';
|
||||
import { FilterColorMatrixType } from '../../lib/extract/types';
|
||||
import FilterPrimitive from './FilterPrimitive';
|
||||
@@ -30,6 +31,7 @@ export default class FeColorMatrix extends FilterPrimitive<FeColorMatrixProps> {
|
||||
this.refMethod(ref as (FeColorMatrix & NativeMethods) | null)
|
||||
}
|
||||
{...extractFilter(this.props)}
|
||||
{...extractIn(this.props)}
|
||||
{...extractFeColorMatrix(this.props)}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -4,6 +4,7 @@ import RNSVGFeGaussianBlur from '../../fabric/FeGaussianBlurNativeComponent';
|
||||
import {
|
||||
extractFeGaussianBlur,
|
||||
extractFilter,
|
||||
extractIn,
|
||||
} from '../../lib/extract/extractFilter';
|
||||
import { FilterEdgeMode, NumberProp } from '../../lib/extract/types';
|
||||
import FilterPrimitive from './FilterPrimitive';
|
||||
@@ -33,6 +34,7 @@ export default class FeGaussianBlur extends FilterPrimitive<FeGaussianBlurProps>
|
||||
this.refMethod(ref as (FeGaussianBlur & NativeMethods) | null)
|
||||
}
|
||||
{...extractFilter(this.props)}
|
||||
{...extractIn(this.props)}
|
||||
{...extractFeGaussianBlur(this.props)}
|
||||
/>
|
||||
);
|
||||
|
||||
27
src/elements/filters/FeMerge.tsx
Normal file
27
src/elements/filters/FeMerge.tsx
Normal file
@@ -0,0 +1,27 @@
|
||||
import * as React from 'react';
|
||||
import { NativeMethods } from 'react-native';
|
||||
import RNSVGFeMerge from '../../fabric/FeMergeNativeComponent';
|
||||
import { extractFeMerge, extractFilter } from '../../lib/extract/extractFilter';
|
||||
import FilterPrimitive from './FilterPrimitive';
|
||||
|
||||
export interface FeMergeProps {
|
||||
children?: React.ReactElement | Array<React.ReactElement>;
|
||||
}
|
||||
|
||||
export default class FeMerge extends FilterPrimitive<FeMergeProps> {
|
||||
static displayName = 'FeMerge';
|
||||
|
||||
static defaultProps = {
|
||||
...this.defaultPrimitiveProps,
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<RNSVGFeMerge
|
||||
ref={(ref) => this.refMethod(ref as (FeMerge & NativeMethods) | null)}
|
||||
{...extractFilter(this.props)}
|
||||
{...extractFeMerge(this.props, this)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
23
src/elements/filters/FeMergeNode.tsx
Normal file
23
src/elements/filters/FeMergeNode.tsx
Normal file
@@ -0,0 +1,23 @@
|
||||
import * as React from 'react';
|
||||
import FilterPrimitive from './FilterPrimitive';
|
||||
|
||||
export interface FeMergeNodeProps {
|
||||
in?: string;
|
||||
parent?: React.Component;
|
||||
}
|
||||
|
||||
export default class FeMergeNode extends FilterPrimitive<FeMergeNodeProps> {
|
||||
static displayName = 'FeMergeNode';
|
||||
|
||||
// Force update parent
|
||||
setNativeProps = () => {
|
||||
const { parent } = this.props;
|
||||
if (parent) {
|
||||
parent.forceUpdate();
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import * as React from 'react';
|
||||
import { NativeMethods } from 'react-native';
|
||||
import RNSVGFeOffset from '../../fabric/FeOffsetNativeComponent';
|
||||
import { extractFilter } from '../../lib/extract/extractFilter';
|
||||
import { extractFilter, extractIn } from '../../lib/extract/extractFilter';
|
||||
import { NumberProp } from '../../lib/extract/types';
|
||||
import FilterPrimitive from './FilterPrimitive';
|
||||
|
||||
@@ -26,6 +26,7 @@ export default class FeOffset extends FilterPrimitive<FeOffsetProps> {
|
||||
ref={(ref) => this.refMethod(ref as (FeOffset & NativeMethods) | null)}
|
||||
{...this.props}
|
||||
{...extractFilter(this.props)}
|
||||
{...extractIn(this.props)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
19
src/fabric/FeMergeNativeComponent.ts
Normal file
19
src/fabric/FeMergeNativeComponent.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';
|
||||
import type { ViewProps } from './utils';
|
||||
|
||||
import { NumberProp } from '../lib/extract/types';
|
||||
import type { UnsafeMixed } from './codegenUtils';
|
||||
|
||||
interface FilterPrimitiveCommonProps {
|
||||
x?: UnsafeMixed<NumberProp>;
|
||||
y?: UnsafeMixed<NumberProp>;
|
||||
width?: UnsafeMixed<NumberProp>;
|
||||
height?: UnsafeMixed<NumberProp>;
|
||||
result?: string;
|
||||
}
|
||||
|
||||
export interface NativeProps extends ViewProps, FilterPrimitiveCommonProps {
|
||||
nodes?: ReadonlyArray<UnsafeMixed<string | undefined>>;
|
||||
}
|
||||
|
||||
export default codegenNativeComponent<NativeProps>('RNSVGFeMerge');
|
||||
@@ -23,6 +23,7 @@ import RNSVGUse from './UseNativeComponent';
|
||||
import RNSVGFilter from './FilterNativeComponent';
|
||||
import RNSVGFeColorMatrix from './FeColorMatrixNativeComponent';
|
||||
import RNSVGFeGaussianBlur from './FeGaussianBlurNativeComponent';
|
||||
import RNSVGFeMerge from './FeMergeNativeComponent';
|
||||
import RNSVGFeOffset from './FeOffsetNativeComponent';
|
||||
|
||||
export {
|
||||
@@ -51,5 +52,6 @@ export {
|
||||
RNSVGFilter,
|
||||
RNSVGFeColorMatrix,
|
||||
RNSVGFeGaussianBlur,
|
||||
RNSVGFeMerge,
|
||||
RNSVGFeOffset,
|
||||
};
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import React from 'react';
|
||||
import { FeColorMatrixProps as FeColorMatrixComponentProps } from '../../elements/filters/FeColorMatrix';
|
||||
import { FeGaussianBlurProps as FeGaussianBlurComponentProps } from '../../elements/filters/FeGaussianBlur';
|
||||
import { FeMergeProps as FeMergeComponentProps } from '../../elements/filters/FeMerge';
|
||||
import { NativeProps as FeColorMatrixNativeProps } from '../../fabric/FeColorMatrixNativeComponent';
|
||||
import { NativeProps as FeGaussianBlurNativeProps } from '../../fabric/FeGaussianBlurNativeComponent';
|
||||
import { NativeProps as FeMergeNativeProps } from '../../fabric/FeMergeNativeComponent';
|
||||
import { NumberProp } from './types';
|
||||
|
||||
const spaceReg = /\s+/;
|
||||
@@ -29,14 +32,18 @@ export const extractFilter = (
|
||||
return extracted;
|
||||
};
|
||||
|
||||
export const extractIn = (props: { in?: string }) => {
|
||||
if (props.in) {
|
||||
return { in1: props.in };
|
||||
}
|
||||
return {};
|
||||
};
|
||||
|
||||
export const extractFeColorMatrix = (
|
||||
props: FeColorMatrixComponentProps
|
||||
): FeColorMatrixNativeProps => {
|
||||
const extracted: FeColorMatrixNativeProps = {};
|
||||
|
||||
if (props.in) {
|
||||
extracted.in1 = props.in;
|
||||
}
|
||||
if (props.values !== undefined) {
|
||||
if (Array.isArray(props.values)) {
|
||||
extracted.values = props.values;
|
||||
@@ -63,9 +70,6 @@ export const extractFeGaussianBlur = (
|
||||
): FeGaussianBlurNativeProps => {
|
||||
const extracted: FeGaussianBlurNativeProps = {};
|
||||
|
||||
if (props.in) {
|
||||
extracted.in1 = props.in;
|
||||
}
|
||||
if (
|
||||
typeof props.stdDeviation === 'string' &&
|
||||
props.stdDeviation.match(spaceReg)
|
||||
@@ -86,3 +90,24 @@ export const extractFeGaussianBlur = (
|
||||
}
|
||||
return extracted;
|
||||
};
|
||||
|
||||
export const extractFeMerge = (
|
||||
props: FeMergeComponentProps,
|
||||
parent: unknown
|
||||
): FeMergeNativeProps => {
|
||||
const nodes: Array<string | undefined> = [];
|
||||
const childArray = props.children
|
||||
? React.Children.map(props.children, (child) =>
|
||||
React.cloneElement(child, { parent })
|
||||
)
|
||||
: [];
|
||||
const l = childArray.length;
|
||||
for (let i = 0; i < l; i++) {
|
||||
const {
|
||||
props: { in: in1 },
|
||||
} = childArray[i];
|
||||
nodes.push(in1);
|
||||
}
|
||||
|
||||
return { nodes };
|
||||
};
|
||||
|
||||
@@ -5,6 +5,8 @@ import {
|
||||
Ellipse,
|
||||
FeColorMatrix,
|
||||
FeGaussianBlur,
|
||||
FeMerge,
|
||||
FeMergeNode,
|
||||
FeOffset,
|
||||
Filter,
|
||||
ForeignObject,
|
||||
@@ -37,6 +39,8 @@ export const tags = {
|
||||
filter: Filter,
|
||||
feColorMatrix: FeColorMatrix,
|
||||
feGaussianBlur: FeGaussianBlur,
|
||||
feMerge: FeMerge,
|
||||
feMergeNode: FeMergeNode,
|
||||
feOffset: FeOffset,
|
||||
foreignObject: ForeignObject,
|
||||
g: G,
|
||||
|
||||
Reference in New Issue
Block a user