diff --git a/USAGE.md b/USAGE.md index 3590bb986..1eeecac9a 100644 --- a/USAGE.md +++ b/USAGE.md @@ -1261,6 +1261,7 @@ Currently supported\* filters are: - FeColorMatrix - FeGaussianBlur +- FeMerge - FeOffset \*_More filters are coming soon_ diff --git a/android/src/main/java/com/horcrux/svg/FeMergeView.java b/android/src/main/java/com/horcrux/svg/FeMergeView.java new file mode 100644 index 000000000..80de0860b --- /dev/null +++ b/android/src/main/java/com/horcrux/svg/FeMergeView.java @@ -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 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; + } +} diff --git a/android/src/main/java/com/horcrux/svg/RenderableViewManager.java b/android/src/main/java/com/horcrux/svg/RenderableViewManager.java index c3d542abf..29600925f 100644 --- a/android/src/main/java/com/horcrux/svg/RenderableViewManager.java +++ b/android/src/main/java/com/horcrux/svg/RenderableViewManager.java @@ -107,6 +107,8 @@ 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 @@ protected enum SVGClass { RNSVGFilter, RNSVGFeColorMatrix, RNSVGFeGaussianBlur, + RNSVGFeMerge, RNSVGFeOffset, RNSVGMarker, RNSVGForeignObject, @@ -640,6 +643,8 @@ protected VirtualView createViewInstance(@Nonnull ThemedReactContext reactContex 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 @@ public void setEdgeMode(FeGaussianBlurView node, String edgeMode) { } } + static class FeMergeManager extends FilterPrimitiveManager + implements RNSVGFeMergeManagerInterface { + 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 implements RNSVGFeOffsetManagerInterface { FeOffsetManager() { diff --git a/android/src/main/java/com/horcrux/svg/SvgPackage.java b/android/src/main/java/com/horcrux/svg/SvgPackage.java index e6e91e1af..21cfa39eb 100644 --- a/android/src/main/java/com/horcrux/svg/SvgPackage.java +++ b/android/src/main/java/com/horcrux/svg/SvgPackage.java @@ -232,6 +232,15 @@ public NativeModule get() { return new FeGaussianBlurManager(); } })); + specs.put( + FeMergeManager.REACT_CLASS, + ModuleSpec.viewManagerSpec( + new Provider() { + @Override + public NativeModule get() { + return new FeMergeManager(); + } + })); specs.put( FeOffsetManager.REACT_CLASS, ModuleSpec.viewManagerSpec( diff --git a/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGFeMergeManagerDelegate.java b/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGFeMergeManagerDelegate.java new file mode 100644 index 000000000..743133a38 --- /dev/null +++ b/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGFeMergeManagerDelegate.java @@ -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 & RNSVGFeMergeManagerInterface> extends BaseViewManagerDelegate { + 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); + } + } +} diff --git a/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGFeMergeManagerInterface.java b/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGFeMergeManagerInterface.java new file mode 100644 index 000000000..172163910 --- /dev/null +++ b/android/src/paper/java/com/facebook/react/viewmanagers/RNSVGFeMergeManagerInterface.java @@ -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 { + 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); +} diff --git a/apple/Filters/RNSVGFeMerge.h b/apple/Filters/RNSVGFeMerge.h new file mode 100644 index 000000000..8e9608855 --- /dev/null +++ b/apple/Filters/RNSVGFeMerge.h @@ -0,0 +1,7 @@ +#import "RNSVGFilterPrimitive.h" + +@interface RNSVGFeMerge : RNSVGFilterPrimitive + +@property (nonatomic, copy) NSArray *nodes; + +@end diff --git a/apple/Filters/RNSVGFeMerge.mm b/apple/Filters/RNSVGFeMerge.mm new file mode 100644 index 000000000..0ec05794a --- /dev/null +++ b/apple/Filters/RNSVGFeMerge.mm @@ -0,0 +1,105 @@ +#import "RNSVGFeMerge.h" + +#ifdef RCT_NEW_ARCH_ENABLED +#import +#import +#import +#import +#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(); + _props = defaultProps; + } + return self; +} + +#pragma mark - RCTComponentViewProtocol + ++ (ComponentDescriptorProvider)componentDescriptorProvider +{ + return concreteComponentDescriptorProvider(); +} + +- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps +{ + const auto &newProps = static_cast(*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(props); +} + +- (void)prepareForRecycle +{ + [super prepareForRecycle]; + _nodes = nil; +} +#endif // RCT_NEW_ARCH_ENABLED + +- (void)setNodes:(NSArray *)nodes +{ + if (nodes == _nodes) { + return; + } + + _nodes = nodes; + [self invalidate]; +} + +- (CIImage *)applyFilter:(NSMutableDictionary *)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 RNSVGFeMergeCls(void) +{ + return RNSVGFeMerge.class; +} +#endif // RCT_NEW_ARCH_ENABLED + +@end diff --git a/apple/ViewManagers/RNSVGFeMergeManager.h b/apple/ViewManagers/RNSVGFeMergeManager.h new file mode 100644 index 000000000..e5539b3bc --- /dev/null +++ b/apple/ViewManagers/RNSVGFeMergeManager.h @@ -0,0 +1,5 @@ +#import "RNSVGFilterPrimitiveManager.h" + +@interface RNSVGFeMergeManager : RNSVGFilterPrimitiveManager + +@end diff --git a/apple/ViewManagers/RNSVGFeMergeManager.mm b/apple/ViewManagers/RNSVGFeMergeManager.mm new file mode 100644 index 000000000..0706941f9 --- /dev/null +++ b/apple/ViewManagers/RNSVGFeMergeManager.mm @@ -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) + +@end diff --git a/apps/examples/src/examples/Filters/FeMerge.tsx b/apps/examples/src/examples/Filters/FeMerge.tsx new file mode 100644 index 000000000..02a428d30 --- /dev/null +++ b/apps/examples/src/examples/Filters/FeMerge.tsx @@ -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 ( + + + + + + + + + + + + + ); + } +} + +class WithHueRotateExample extends Component { + static title = 'Merge with SourceGraphic and HueRotate'; + render() { + return ( + + + + + + + + + + + + ); + } +} + +const icon = ( + + + + + + + + + + +); + +const samples = [WithOffsetsExample, WithHueRotateExample]; +export {icon, samples}; diff --git a/apps/examples/src/examples/Filters/examples.tsx b/apps/examples/src/examples/Filters/examples.tsx index 065780f19..e71d053ec 100644 --- a/apps/examples/src/examples/Filters/examples.tsx +++ b/apps/examples/src/examples/Filters/examples.tsx @@ -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, +}; diff --git a/react-native.config.js b/react-native.config.js index eeec98f13..28470fcd2 100644 --- a/react-native.config.js +++ b/react-native.config.js @@ -19,6 +19,7 @@ module.exports = { 'RNSVGDefsComponentDescriptor', 'RNSVGFeColorMatrixComponentDescriptor', 'RNSVGFeGaussianBlurComponentDescriptor', + 'RNSVGFeMergeComponentDescriptor', 'RNSVGFeOffsetComponentDescriptor', 'RNSVGFilterComponentDescriptor', 'RNSVGEllipseComponentDescriptor', diff --git a/src/ReactNativeSVG.ts b/src/ReactNativeSVG.ts index 790e4e353..cc4bc1cdb 100644 --- a/src/ReactNativeSVG.ts +++ b/src/ReactNativeSVG.ts @@ -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, diff --git a/src/elements.ts b/src/elements.ts index daa110dc4..19b01d020 100644 --- a/src/elements.ts +++ b/src/elements.ts @@ -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, diff --git a/src/elements.web.ts b/src/elements.web.ts index 7dc928755..34a348e6a 100644 --- a/src/elements.web.ts +++ b/src/elements.web.ts @@ -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 { tag = 'feGaussianBlur' as const; } +export class FeMerge extends WebShape { + tag = 'feMerge' as const; +} + +export class FeMergeNode extends WebShape { + tag = 'feMergeNode' as const; +} + export class FeOffset extends WebShape { tag = 'feOffset' as const; } diff --git a/src/elements/filters/FeColorMatrix.tsx b/src/elements/filters/FeColorMatrix.tsx index e40d4db25..586edfc66 100644 --- a/src/elements/filters/FeColorMatrix.tsx +++ b/src/elements/filters/FeColorMatrix.tsx @@ -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 { this.refMethod(ref as (FeColorMatrix & NativeMethods) | null) } {...extractFilter(this.props)} + {...extractIn(this.props)} {...extractFeColorMatrix(this.props)} /> ); diff --git a/src/elements/filters/FeGaussianBlur.tsx b/src/elements/filters/FeGaussianBlur.tsx index 4158c02e4..cf6553f56 100644 --- a/src/elements/filters/FeGaussianBlur.tsx +++ b/src/elements/filters/FeGaussianBlur.tsx @@ -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 this.refMethod(ref as (FeGaussianBlur & NativeMethods) | null) } {...extractFilter(this.props)} + {...extractIn(this.props)} {...extractFeGaussianBlur(this.props)} /> ); diff --git a/src/elements/filters/FeMerge.tsx b/src/elements/filters/FeMerge.tsx new file mode 100644 index 000000000..2dddfa2ed --- /dev/null +++ b/src/elements/filters/FeMerge.tsx @@ -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; +} + +export default class FeMerge extends FilterPrimitive { + static displayName = 'FeMerge'; + + static defaultProps = { + ...this.defaultPrimitiveProps, + }; + + render() { + return ( + this.refMethod(ref as (FeMerge & NativeMethods) | null)} + {...extractFilter(this.props)} + {...extractFeMerge(this.props, this)} + /> + ); + } +} diff --git a/src/elements/filters/FeMergeNode.tsx b/src/elements/filters/FeMergeNode.tsx new file mode 100644 index 000000000..0aa85e3dc --- /dev/null +++ b/src/elements/filters/FeMergeNode.tsx @@ -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 { + static displayName = 'FeMergeNode'; + + // Force update parent + setNativeProps = () => { + const { parent } = this.props; + if (parent) { + parent.forceUpdate(); + } + }; + + render() { + return null; + } +} diff --git a/src/elements/filters/FeOffset.tsx b/src/elements/filters/FeOffset.tsx index 14703fd6d..91d9952e4 100644 --- a/src/elements/filters/FeOffset.tsx +++ b/src/elements/filters/FeOffset.tsx @@ -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 { ref={(ref) => this.refMethod(ref as (FeOffset & NativeMethods) | null)} {...this.props} {...extractFilter(this.props)} + {...extractIn(this.props)} /> ); } diff --git a/src/fabric/FeMergeNativeComponent.ts b/src/fabric/FeMergeNativeComponent.ts new file mode 100644 index 000000000..68b403a7c --- /dev/null +++ b/src/fabric/FeMergeNativeComponent.ts @@ -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; + y?: UnsafeMixed; + width?: UnsafeMixed; + height?: UnsafeMixed; + result?: string; +} + +export interface NativeProps extends ViewProps, FilterPrimitiveCommonProps { + nodes?: ReadonlyArray>; +} + +export default codegenNativeComponent('RNSVGFeMerge'); diff --git a/src/fabric/index.ts b/src/fabric/index.ts index 779597cc1..8cdbb4f77 100644 --- a/src/fabric/index.ts +++ b/src/fabric/index.ts @@ -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, }; diff --git a/src/lib/extract/extractFilter.ts b/src/lib/extract/extractFilter.ts index 14aca225a..e2f441ba4 100644 --- a/src/lib/extract/extractFilter.ts +++ b/src/lib/extract/extractFilter.ts @@ -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 = []; + 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 }; +}; diff --git a/src/xmlTags.ts b/src/xmlTags.ts index 25abe8c70..fc34fdb0c 100644 --- a/src/xmlTags.ts +++ b/src/xmlTags.ts @@ -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,