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:
Jakub Grzywacz
2024-07-31 13:23:53 +02:00
committed by GitHub
parent a2e843bc9c
commit b8b022c31e
25 changed files with 508 additions and 9 deletions

View File

@@ -1261,6 +1261,7 @@ Currently supported\* filters are:
- FeColorMatrix
- FeGaussianBlur
- FeMerge
- FeOffset
\*_More filters are coming soon_

View 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;
}
}

View File

@@ -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() {

View File

@@ -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(

View File

@@ -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);
}
}
}

View File

@@ -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);
}

View File

@@ -0,0 +1,7 @@
#import "RNSVGFilterPrimitive.h"
@interface RNSVGFeMerge : RNSVGFilterPrimitive
@property (nonatomic, copy) NSArray<NSString *> *nodes;
@end

View 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

View File

@@ -0,0 +1,5 @@
#import "RNSVGFilterPrimitiveManager.h"
@interface RNSVGFeMergeManager : RNSVGFilterPrimitiveManager
@end

View 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

View 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};

View File

@@ -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,
};

View File

@@ -19,6 +19,7 @@ module.exports = {
'RNSVGDefsComponentDescriptor',
'RNSVGFeColorMatrixComponentDescriptor',
'RNSVGFeGaussianBlurComponentDescriptor',
'RNSVGFeMergeComponentDescriptor',
'RNSVGFeOffsetComponentDescriptor',
'RNSVGFilterComponentDescriptor',
'RNSVGEllipseComponentDescriptor',

View File

@@ -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,

View File

@@ -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,

View File

@@ -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;
}

View File

@@ -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)}
/>
);

View File

@@ -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)}
/>
);

View 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)}
/>
);
}
}

View 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;
}
}

View File

@@ -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)}
/>
);
}

View 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');

View File

@@ -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,
};

View File

@@ -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 };
};

View File

@@ -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,