Skip to content
This repository was archived by the owner on Oct 8, 2021. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,9 @@ protected boolean setupStrokePaint(Paint paint, float opacity) {
if (mStrokeDash != null && mStrokeDash.length > 0) {
paint.setPathEffect(new DashPathEffect(mStrokeDash, 0));
}
if (mShadowOpacity > 0) {
paint.setShadowLayer(mShadowRadius, mShadowOffsetX, mShadowOffsetY, mShadowColor);
}
return true;
}

Expand Down Expand Up @@ -231,6 +234,9 @@ protected boolean setupFillPaint(Paint paint, float opacity) {
default:
FLog.w(ReactConstants.TAG, "ART: Color type " + colorType + " not supported!");
}
if (mShadowOpacity > 0) {
paint.setShadowLayer(mShadowRadius, mShadowOffsetX, mShadowOffsetY, mShadowColor);
}
return true;
}
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,9 @@ public void draw(Canvas canvas, Paint paint, float opacity) {
canvas.drawTextOnPath(text, mPath, 0, 0, paint);
}
}
if (mShadowOpacity > 0) {
paint.setShadowLayer(mShadowRadius, mShadowOffsetX, mShadowOffsetY, mShadowColor);
}
restoreCanvas(canvas);
markUpdateSeen();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,11 @@
package com.reactnativecommunity.art;

import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.support.v4.graphics.ColorUtils;

import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.uimanager.DisplayMetricsHolder;
Expand All @@ -30,6 +33,11 @@ public abstract class ARTVirtualNode extends ReactShadowNodeImpl {

protected float mOpacity = 1f;
private @Nullable Matrix mMatrix = new Matrix();
protected int mShadowColor = 0;
protected float mShadowOpacity = 1;
protected float mShadowRadius = 0;
protected float mShadowOffsetX = 0;
protected float mShadowOffsetY = 0;

protected final float mScale;

Expand Down Expand Up @@ -91,6 +99,32 @@ public void setTransform(@Nullable ReadableArray transformArray) {
markUpdated();
}

@ReactProp(name = "shadow")
public void setShadow(@Nullable ReadableArray shadowArray) {
if (shadowArray != null) {
mShadowOpacity = (float)shadowArray.getDouble(1);
mShadowRadius = (float)shadowArray.getDouble(2);
mShadowOffsetX = (float)shadowArray.getDouble(3);
mShadowOffsetY = (float)shadowArray.getDouble(4);

int color = shadowArray.getInt(0);

if (mShadowOpacity < 1) {
color = ColorUtils.setAlphaComponent(color, (int)(mShadowOpacity * 255));
}

mShadowColor = color;

} else {
mShadowColor = 0;
mShadowOpacity = 0;
mShadowRadius = 0;
mShadowOffsetX = 0;
mShadowOffsetY = 0;
}
markUpdated();
}

protected void setupMatrix() {
sRawMatrix[0] = sMatrixData[0];
sRawMatrix[1] = sMatrixData[2];
Expand Down
23 changes: 21 additions & 2 deletions docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ Container to combine shapes or other groups into hierarchies that can be transfo
| :---------------: | :-----------------------------------: | :-----: |
| ...opacityProps | [`OpacityProps`](###OpacityProps) | --- |
| ...transformProps | [`TransformProps`](###TransformProps) | --- |
| ...shadowProps | [`ShadowProps`](###ShadowProps) | --- |
| children | `React.Node` | --- |

```jsx
Expand All @@ -53,7 +54,8 @@ Used to draw arbitrary vector shapes from Path. Shape implements Transform as a
| :---------------: | :-----------------------------------: | :-------: |
| ...opacityProps | [`OpacityProps`](###OpacityProps) | --- |
| ...transformProps | [`TransformProps`](###TransformProps) | --- |
| fill | `string \| Brush` | --- |
| ...shadowProps | [`ShadowProps`](###ShadowProps) | --- |
| fill | `string \| Brush` | --- |
| stroke | `string` | --- |
| strokeCap | `'butt' \| 'square' \| 'round'` | `'round'` |
| strokeDash | `Array<number>` | --- |
Expand Down Expand Up @@ -84,7 +86,8 @@ Text component creates a shape based on text content using native text rendering
| :---------------: | :-----------------------------------: | :-------: |
| ...opacityProps | [`OpacityProps`](###OpacityProps) | --- |
| ...transformProps | [`TransformProps`](###TransformProps) | --- |
| fill | `string \| Brush` | --- |
| ...shadowProps | [`ShadowProps`](###ShadowProps) | --- |
| fill | `string \| Brush` | --- |
| stroke | `string` | --- |
| strokeCap | `'butt' \| 'square' \| 'round'` | `'round'` |
| strokeDash | `Array<number>` | --- |
Expand Down Expand Up @@ -354,6 +357,22 @@ function Component() {
| originY | `number` | --- |
| transform | `TransformObject` | --- |

### ShadowProps

| Prop | Type | Default |
| :-----------: | :------------------: | :------: |
| shadowOpacity | `number` | `1` |
| shadowColor | `string` | `black` |
| shadowRadius | `number` | `0` |
| shadowOffset | `ShadowOffsetObject` | --- |

### ShadowOffsetObject

| Prop | Type | Default |
| :--: | :------: | :-----: |
| y | `number` | `0` |
| x | `number` | `0` |

### Font

| Prop | Type | Default |
Expand Down
12 changes: 11 additions & 1 deletion example/components/CustomText.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,24 @@ import React from 'react';
import {Dimensions, StyleSheet} from 'react-native';
import {Surface, Text, Group} from '@react-native-community/art';

const SHADOW = {
shadowOpacity: 0.5,
shadowColor: 'blue',
shadowRadius: 10,
shadowOffset: {x: 4, y: 4},
};

export default function CustomText() {
const surfaceWidth = Dimensions.get('window').width;
const surfaceHeight = surfaceWidth / 3;

return (
<Surface width={surfaceWidth} height={surfaceHeight} style={styles.surface}>
<Group x={surfaceWidth / 2 - 100} y={surfaceHeight / 2}>
<Text font={'18px "Helvetica Neue", "Helvetica", Arial'} fill="#000000">
<Text
font={'18px "Helvetica Neue", "Helvetica", Arial'}
fill="#000000"
{...SHADOW}>
React Native Community
</Text>
</Group>
Expand Down
8 changes: 8 additions & 0 deletions example/components/Heart.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,13 @@ import {
const HEART_SHAPE =
'M 10,30 A 20,20 0,0,1 50,30 A 20,20 0,0,1 90,30 Q 90,60 50,90 Q 10,60 10,30 z';

const SHADOW = {
shadowOpacity: 1,
shadowColor: 'red',
shadowRadius: 8,
shadowOffset: {x: 0, y: 0},
};

export default function Heart() {
const surfaceDimensions = Dimensions.get('window').width;
const gradient = new RadialGradient(
Expand Down Expand Up @@ -42,6 +49,7 @@ export default function Heart() {
stroke={'#00ff00'}
fill={gradient}
visible={true}
{...SHADOW}
/>
</Group>
</Surface>
Expand Down
7 changes: 7 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,13 @@ declare module '@react-native-community/art' {
x?: number;
y?: number;
visible?: boolean;
shadowOpacity?: number;
shadowColor?: string | number;
shadowRadius?: number;
shadowOffset?: {
x: number,
y: number,
}
}

export interface ARTGroupProps extends ARTNodeMixin {
Expand Down
3 changes: 3 additions & 0 deletions ios/ART.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
/* End PBXCopyFilesBuildPhase section */

/* Begin PBXFileReference section */
09966EAF23996E3900E9C452 /* ARTShadow.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ARTShadow.h; sourceTree = "<group>"; };
0CF68AC11AF0540F00FF9E5C /* libART.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libART.a; sourceTree = BUILT_PRODUCTS_DIR; };
0CF68ADB1AF0549300FF9E5C /* ARTCGFloatArray.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARTCGFloatArray.h; sourceTree = "<group>"; };
0CF68ADC1AF0549300FF9E5C /* ARTContainer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARTContainer.h; sourceTree = "<group>"; };
Expand Down Expand Up @@ -131,6 +132,7 @@
0CF68AB81AF0540F00FF9E5C = {
isa = PBXGroup;
children = (
09966EAF23996E3900E9C452 /* ARTShadow.h */,
0CF68AEA1AF0549300FF9E5C /* Brushes */,
0CF68AF81AF0549300FF9E5C /* ViewManagers */,
0CF68ADB1AF0549300FF9E5C /* ARTCGFloatArray.h */,
Expand Down Expand Up @@ -261,6 +263,7 @@
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
English,
en,
);
mainGroup = 0CF68AB81AF0540F00FF9E5C;
Expand Down
3 changes: 2 additions & 1 deletion ios/ARTNode.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
*/

#import <React/UIView+React.h>

#import "ARTShadow.h"
/**
* ART nodes are implemented as empty UIViews but this is just an implementation detail to fit
* into the existing view management. They should also be shadow views and painted on a background
Expand All @@ -16,6 +16,7 @@
@interface ARTNode : UIView

@property (nonatomic, assign) CGFloat opacity;
@property (nonatomic, assign) ARTShadow shadow;

- (void)invalidate;
- (void)renderTo:(CGContextRef)context;
Expand Down
22 changes: 16 additions & 6 deletions ios/ARTNode.m
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ - (void)setTransform:(CGAffineTransform)transform
super.transform = transform;
}

- (void)setShadow:(ARTShadow)shadow
{
[self invalidate];
_shadow = shadow;
}

- (void)invalidate
{
id<ARTContainer> container = (id<ARTContainer>)self.superview;
Expand All @@ -55,23 +61,27 @@ - (void)renderTo:(CGContextRef)context
}
if (self.opacity >= 1) {
// Just paint at full opacity
CGContextSaveGState(context);
CGContextConcatCTM(context, self.transform);
CGContextSetAlpha(context, 1);
[self renderContentTo:context];
[self renderLayerTo:context];
CGContextRestoreGState(context);
return;
}

// This needs to be painted on a layer before being composited.
CGContextSaveGState(context);
CGContextConcatCTM(context, self.transform);
CGContextSetAlpha(context, self.opacity);
[self renderContentTo:context];
CGContextBeginTransparencyLayer(context, NULL);
[self renderLayerTo:context];
CGContextEndTransparencyLayer(context);
CGContextRestoreGState(context);
}

- (void)renderContentTo:(CGContextRef)context {
CGContextSaveGState(context);
CGContextConcatCTM(context, self.transform);
CGContextSetAlpha(context, self.opacity);
CGContextSetShadowWithColor(context, self.shadow.offset, self.shadow.blur, self.shadow.color.CGColor);
}

- (void)renderLayerTo:(CGContextRef)context
{
// abstract
Expand Down
12 changes: 12 additions & 0 deletions ios/ARTShadow.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/**
* 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.
*/

typedef struct {
CGSize offset;
CGFloat blur;
UIColor* color;
} ARTShadow;
2 changes: 2 additions & 0 deletions ios/RCTConvert+ART.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#import <React/RCTConvert.h>

#import "ARTBrush.h"
#import "ARTShadow.h"
#import "ARTCGFloatArray.h"
#import "ARTTextFrame.h"

Expand All @@ -20,6 +21,7 @@
+ (ARTTextFrame)ARTTextFrame:(id)json;
+ (ARTCGFloatArray)ARTCGFloatArray:(id)json;
+ (ARTBrush *)ARTBrush:(id)json;
+ (ARTShadow)ARTShadow:(id)json;

+ (CGPoint)CGPoint:(id)json offset:(NSUInteger)offset;
+ (CGRect)CGRect:(id)json offset:(NSUInteger)offset;
Expand Down
17 changes: 17 additions & 0 deletions ios/RCTConvert+ART.m
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,23 @@ + (ARTBrush *)ARTBrush:(id)json
}
}

+ (ARTShadow)ARTShadow:(id)json
{
NSArray *arr = [self NSArray:json];

UIColor *color = [UIColor colorWithCGColor:[self CGColor:[arr objectAtIndex:0]]];
color = [color colorWithAlphaComponent:[[arr objectAtIndex:1] floatValue]];

return (ARTShadow){
.color = color,
.blur = [[arr objectAtIndex:2] floatValue],
.offset = (CGSize){
.width = [[arr objectAtIndex:3] floatValue],
.height = [[arr objectAtIndex:4] floatValue]
},
};
}

+ (CGPoint)CGPoint:(id)json offset:(NSUInteger)offset
{
NSArray *arr = [self NSArray:json];
Expand Down
1 change: 1 addition & 0 deletions ios/ViewManagers/ARTNodeManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,6 @@ - (RCTShadowView *)shadowView

RCT_EXPORT_VIEW_PROPERTY(opacity, CGFloat)
RCT_EXPORT_VIEW_PROPERTY(transform, CGAffineTransform)
RCT_EXPORT_VIEW_PROPERTY(shadow, ARTShadow)

@end
23 changes: 13 additions & 10 deletions lib/ClippingRectangle.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,19 @@

import * as React from 'react';
import merge from 'react-native/Libraries/vendor/core/merge';
import {extractOpacity, extractTransform} from './helpers';
import {extractOpacity, extractTransform, extractShadow} from './helpers';
import {NativeGroup} from './nativeComponents';
import type {OpacityProps} from './types';
import type {OpacityProps, TransformProps, ShadowProps} from './types';

type ClippingRectangleProps = OpacityProps & {
x: number,
y: number,
width: number,
height: number,
children?: React.Node,
};
type ClippingRectangleProps = OpacityProps &
TransformProps &
ShadowProps & {
x: number,
y: number,
width: number,
height: number,
children?: React.Node,
};

export default class ClippingRectangle extends React.Component<ClippingRectangleProps> {
static defaultProps = {
Expand All @@ -44,7 +46,8 @@ export default class ClippingRectangle extends React.Component<ClippingRectangle
<NativeGroup
clipping={clipping}
opacity={extractOpacity(this.props)}
transform={extractTransform(propsExcludingXAndY)}>
transform={extractTransform(propsExcludingXAndY)}
shadow={extractShadow(this.props)}>
{this.props.children}
</NativeGroup>
);
Expand Down
Loading