@@ -14,6 +14,7 @@ import { useCustomShapeDrawing } from "./canvas/useCustomShapeDrawing";
|
||||
import { usePencilDrawing } from "./canvas/usePencilDrawing";
|
||||
import ObjectsLayer from "./canvas/ObjectsLayer";
|
||||
import GuidesLayer from "./canvas/GuidesLayer";
|
||||
import BlurBackdropLayer from "./canvas/BlurBackdropLayer";
|
||||
import CustomShapeDrawingLayer from "./canvas/CustomShapeDrawingLayer";
|
||||
import PencilDrawingLayer from "./canvas/PencilDrawingLayer";
|
||||
import {
|
||||
@@ -627,6 +628,13 @@ const EditorCanvas = ({ catalogSize }: EditorCanvasProps) => {
|
||||
<CustomShapeDrawingLayer drawingState={drawingState} />
|
||||
<PencilDrawingLayer drawingState={pencilDrawingState} />
|
||||
</Stage>
|
||||
<BlurBackdropLayer
|
||||
objects={objects}
|
||||
stageWidth={stageSize.width}
|
||||
stageHeight={stageSize.height}
|
||||
scale={finalScale}
|
||||
stageRef={stageRef}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,195 @@
|
||||
import { useEffect, useMemo, useState, type CSSProperties } from "react";
|
||||
import type Konva from "konva";
|
||||
import type { EditorObject } from "../../store/editorStore";
|
||||
import { getColorWithOpacity } from "../../utils/colorOpacity";
|
||||
import { toCssGradientAngle, type LinearGradient } from "../../utils/gradient";
|
||||
|
||||
type BlurBackdropLayerProps = {
|
||||
objects: EditorObject[];
|
||||
stageWidth: number;
|
||||
stageHeight: number;
|
||||
/** Stage scale applied to Konva (editor internal scale + zoom). */
|
||||
scale: number;
|
||||
stageRef: React.RefObject<Konva.Stage | null>;
|
||||
};
|
||||
|
||||
const TRIANGLE_TOP_Y_PERCENT = 6.69873; // (1 - sqrt(3)/2) / 2
|
||||
const TRIANGLE_BOTTOM_Y_PERCENT = 93.30127; // 100 - TRIANGLE_TOP_Y_PERCENT
|
||||
|
||||
const BlurBackdropLayer = ({ objects, stageWidth, stageHeight, scale, stageRef }: BlurBackdropLayerProps) => {
|
||||
const [dragRevision, setDragRevision] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
const stage = stageRef.current;
|
||||
if (!stage) return;
|
||||
|
||||
let raf = 0;
|
||||
const bump = () => setDragRevision((v) => v + 1);
|
||||
|
||||
const scheduleBump = () => {
|
||||
if (raf) return;
|
||||
raf = window.requestAnimationFrame(() => {
|
||||
raf = 0;
|
||||
bump();
|
||||
});
|
||||
};
|
||||
|
||||
const onDragMove = () => scheduleBump();
|
||||
const onDragEnd = () => scheduleBump();
|
||||
|
||||
stage.on("dragmove", onDragMove);
|
||||
stage.on("dragend", onDragEnd);
|
||||
|
||||
return () => {
|
||||
stage.off("dragmove", onDragMove);
|
||||
stage.off("dragend", onDragEnd);
|
||||
if (raf) window.cancelAnimationFrame(raf);
|
||||
};
|
||||
}, [stageRef]);
|
||||
|
||||
const overlays = useMemo(() => {
|
||||
const stage = stageRef.current;
|
||||
|
||||
return objects
|
||||
.map((obj, index) => {
|
||||
if (obj.visible === false) return null;
|
||||
if (obj.isMask) return null;
|
||||
if (obj.type !== "rectangle") return null;
|
||||
|
||||
const blur = obj.blur ?? 0;
|
||||
if (blur <= 0) return null;
|
||||
|
||||
const blurPx = blur * scale;
|
||||
const rotation = obj.rotation ?? 0;
|
||||
const shapeType = obj.shapeType ?? "square";
|
||||
|
||||
// Konva shapes are positioned differently depending on shapeType.
|
||||
let leftPx = 0;
|
||||
let topPx = 0;
|
||||
let widthPx = (obj.width ?? 100) * scale;
|
||||
let heightPx = (obj.height ?? 100) * scale;
|
||||
let borderRadiusPx = 0;
|
||||
let clipPath: string | undefined;
|
||||
let transformOrigin: CSSProperties["transformOrigin"] = "top left";
|
||||
|
||||
const node = stage?.findOne(`#${obj.id}`);
|
||||
const absPos = node && "getAbsolutePosition" in node ? node.getAbsolutePosition() : null;
|
||||
const nodeX = absPos?.x ?? node?.x?.() ?? obj.x ?? 0;
|
||||
const nodeY = absPos?.y ?? node?.y?.() ?? obj.y ?? 0;
|
||||
|
||||
if (shapeType === "circle") {
|
||||
const sizePx = (obj.width ?? 100) * scale;
|
||||
const radiusPx = sizePx / 2;
|
||||
// `getAbsolutePosition()` is already in the same pixel space as our overlay container.
|
||||
// Konva.Circle uses x/y as CENTER coordinates, while our overlay uses top-left.
|
||||
leftPx = nodeX - radiusPx;
|
||||
topPx = nodeY - radiusPx;
|
||||
widthPx = sizePx;
|
||||
heightPx = sizePx;
|
||||
borderRadiusPx = radiusPx;
|
||||
transformOrigin = "center center";
|
||||
} else if (shapeType === "triangle") {
|
||||
const baseWidth = obj.width ?? 100;
|
||||
const baseHeight = obj.height ?? 100;
|
||||
const side = Math.min(baseWidth, baseHeight);
|
||||
const radius = side / 2;
|
||||
const radiusPx = radius * scale;
|
||||
// In Konva TriangleShape, x/y are center coordinates.
|
||||
leftPx = nodeX - radiusPx;
|
||||
topPx = nodeY - radiusPx;
|
||||
widthPx = side * scale;
|
||||
heightPx = side * scale;
|
||||
clipPath = `polygon(50% ${TRIANGLE_TOP_Y_PERCENT}%, 0% ${TRIANGLE_BOTTOM_Y_PERCENT}%, 100% ${TRIANGLE_BOTTOM_Y_PERCENT}%)`;
|
||||
transformOrigin = "center center";
|
||||
} else if (shapeType === "abstract") {
|
||||
const rawW = obj.width ?? 100;
|
||||
const rawH = obj.height ?? 100;
|
||||
const width = rawW * scale;
|
||||
const height = rawH * scale;
|
||||
|
||||
const baseRadius = Math.min(width, height) / 2;
|
||||
const abstractScale = 0.85;
|
||||
const radius = baseRadius * abstractScale;
|
||||
|
||||
// In Konva AbstractShape, x/y are center coordinates.
|
||||
const centerX = nodeX;
|
||||
const centerY = nodeY;
|
||||
leftPx = centerX - radius;
|
||||
topPx = centerY - radius;
|
||||
widthPx = radius * 2;
|
||||
heightPx = radius * 2;
|
||||
clipPath =
|
||||
"polygon(50% 0%, 61% 35%, 98% 35%, 68% 57%, 79% 91%, 50% 70%, 21% 91%, 32% 57%, 2% 35%, 39% 35%)";
|
||||
transformOrigin = "center center";
|
||||
} else {
|
||||
// rectangle / square (Konva Rect uses x/y as top-left).
|
||||
leftPx = nodeX;
|
||||
topPx = nodeY;
|
||||
widthPx = (obj.width ?? 100) * scale;
|
||||
heightPx = (obj.height ?? 100) * scale;
|
||||
borderRadiusPx = Math.max(0, obj.borderRadius ?? 0) * scale;
|
||||
transformOrigin = "0% 0%";
|
||||
}
|
||||
|
||||
const objOpacity = obj.opacity ?? 100; // 0-100 (editor convention)
|
||||
// Make blur tint translucent so the backdrop blur stays visible.
|
||||
const BLUR_TINT_OPACITY_FACTOR = 0.25;
|
||||
const tintOpacity = Math.max(0, Math.min(100, objOpacity * BLUR_TINT_OPACITY_FACTOR));
|
||||
const defaultFill = "#3b82f6";
|
||||
|
||||
const overlayBackground: CSSProperties =
|
||||
obj.fillType === "gradient" && obj.gradient
|
||||
? (() => {
|
||||
const g = obj.gradient as LinearGradient;
|
||||
const angle = toCssGradientAngle(g.angle);
|
||||
const from = getColorWithOpacity(g.from, tintOpacity);
|
||||
const to = getColorWithOpacity(g.to, tintOpacity);
|
||||
return {
|
||||
backgroundImage: `linear-gradient(${angle}deg, ${from} 0%, ${to} 100%)`,
|
||||
backgroundColor: "transparent",
|
||||
};
|
||||
})()
|
||||
: {
|
||||
backgroundColor: getColorWithOpacity(obj.fill ?? defaultFill, tintOpacity),
|
||||
};
|
||||
|
||||
const style: CSSProperties = {
|
||||
position: "absolute",
|
||||
left: `${leftPx}px`,
|
||||
top: `${topPx}px`,
|
||||
width: `${widthPx}px`,
|
||||
height: `${heightPx}px`,
|
||||
zIndex: index,
|
||||
pointerEvents: "none",
|
||||
backdropFilter: `blur(${blurPx}px)`,
|
||||
WebkitBackdropFilter: `blur(${blurPx}px)`,
|
||||
...overlayBackground,
|
||||
overflow: clipPath ? "hidden" : borderRadiusPx > 0 ? "hidden" : undefined,
|
||||
borderRadius: borderRadiusPx > 0 ? `${borderRadiusPx}px` : undefined,
|
||||
clipPath,
|
||||
transform: rotation ? `rotate(${rotation}deg)` : undefined,
|
||||
transformOrigin,
|
||||
};
|
||||
|
||||
return <div key={`blur-backdrop-${obj.id}`} style={style} />;
|
||||
})
|
||||
;
|
||||
}, [objects, scale, dragRevision, stageRef]);
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
inset: 0,
|
||||
width: stageWidth * scale,
|
||||
height: stageHeight * scale,
|
||||
pointerEvents: "none",
|
||||
}}
|
||||
>
|
||||
{overlays}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default BlurBackdropLayer;
|
||||
|
||||
@@ -3,7 +3,8 @@ import { Star } from "react-konva";
|
||||
import Konva from "konva";
|
||||
import type { ShapeProps } from "./types";
|
||||
import { getKonvaGradientProps } from "../../utils/gradient";
|
||||
import { getKonvaBlurProps, useShapeBlurCache } from "../../utils/shapeBlur";
|
||||
import { getColorWithOpacity } from "../../utils/colorOpacity";
|
||||
import { useShapeBlurCache } from "../../utils/shapeBlur";
|
||||
|
||||
const AbstractShape = ({ obj, isSelected, onSelect, onUpdate, draggable }: ShapeProps) => {
|
||||
const shapeRef = useRef<Konva.Star>(null);
|
||||
@@ -19,9 +20,13 @@ const AbstractShape = ({ obj, isSelected, onSelect, onUpdate, draggable }: Shape
|
||||
|
||||
const actualStrokeWidth = obj.strokeWidth ?? 0;
|
||||
const hasStroke = actualStrokeWidth > 0;
|
||||
const blurProps = isMask ? {} : getKonvaBlurProps(obj.blur);
|
||||
const blurRadius = obj.blur ?? 0;
|
||||
const blurHitFill = blurRadius > 0 ? getColorWithOpacity(obj.fill ?? "#000000", 0.5) : undefined;
|
||||
// Editor blur is implemented via backdrop-filter (see BlurBackdropLayer).
|
||||
// Avoid applying Konva blur filters on the element itself.
|
||||
const blurProps = {};
|
||||
|
||||
useShapeBlurCache(shapeRef, isMask ? 0 : obj.blur, [
|
||||
useShapeBlurCache(shapeRef, 0, [
|
||||
obj.width,
|
||||
obj.height,
|
||||
obj.fill,
|
||||
@@ -29,7 +34,6 @@ const AbstractShape = ({ obj, isSelected, onSelect, onUpdate, draggable }: Shape
|
||||
obj.gradient,
|
||||
obj.stroke,
|
||||
actualStrokeWidth,
|
||||
obj.blur,
|
||||
]);
|
||||
|
||||
// برای نمایش انتخاب: اگر strokeWidth واقعی > 0 است، از آن استفاده کن، وگرنه stroke را برای انتخاب نمایش بده
|
||||
@@ -44,14 +48,14 @@ const AbstractShape = ({ obj, isSelected, onSelect, onUpdate, draggable }: Shape
|
||||
const displayStrokeWidth = isSelected
|
||||
? (hasStroke ? actualStrokeWidth : 3)
|
||||
: (isMask && showGuide ? 2 : actualStrokeWidth);
|
||||
const gradientProps = isMask
|
||||
? {}
|
||||
: getKonvaGradientProps(
|
||||
obj.fillType,
|
||||
obj.gradient,
|
||||
obj.width || 100,
|
||||
obj.height || 100,
|
||||
"centered",
|
||||
const gradientProps = isMask || blurRadius > 0
|
||||
? {}
|
||||
: getKonvaGradientProps(
|
||||
obj.fillType,
|
||||
obj.gradient,
|
||||
obj.width || 100,
|
||||
obj.height || 100,
|
||||
"centered",
|
||||
);
|
||||
|
||||
return (
|
||||
@@ -64,7 +68,8 @@ const AbstractShape = ({ obj, isSelected, onSelect, onUpdate, draggable }: Shape
|
||||
numPoints={5}
|
||||
innerRadius={innerRadius}
|
||||
outerRadius={radius}
|
||||
fill={isMask ? "transparent" : obj.fill}
|
||||
// When blur is enabled, tint is rendered by BlurBackdropLayer.
|
||||
fill={isMask ? "transparent" : blurRadius > 0 ? blurHitFill : (obj.fill ?? "#000000")}
|
||||
{...gradientProps}
|
||||
stroke={displayStroke}
|
||||
strokeWidth={displayStrokeWidth}
|
||||
|
||||
@@ -3,7 +3,8 @@ import { Circle } from "react-konva";
|
||||
import Konva from "konva";
|
||||
import type { ShapeProps } from "./types";
|
||||
import { getKonvaGradientProps } from "../../utils/gradient";
|
||||
import { getKonvaBlurProps, useShapeBlurCache } from "../../utils/shapeBlur";
|
||||
import { getColorWithOpacity } from "../../utils/colorOpacity";
|
||||
import { useShapeBlurCache } from "../../utils/shapeBlur";
|
||||
|
||||
const CircleShape = ({ obj, isSelected, onSelect, onUpdate, draggable }: ShapeProps) => {
|
||||
const shapeRef = useRef<Konva.Circle>(null);
|
||||
@@ -15,16 +16,19 @@ const CircleShape = ({ obj, isSelected, onSelect, onUpdate, draggable }: ShapePr
|
||||
|
||||
const actualStrokeWidth = obj.strokeWidth ?? 0;
|
||||
const hasStroke = actualStrokeWidth > 0;
|
||||
const blurProps = isMask ? {} : getKonvaBlurProps(obj.blur);
|
||||
const blurRadius = obj.blur ?? 0;
|
||||
const blurHitFill = blurRadius > 0 ? getColorWithOpacity(obj.fill ?? "#000000", 0.5) : undefined;
|
||||
// Editor blur is implemented via backdrop-filter (see BlurBackdropLayer).
|
||||
// Avoid applying Konva blur filters on the element itself.
|
||||
const blurProps = {};
|
||||
|
||||
useShapeBlurCache(shapeRef, isMask ? 0 : obj.blur, [
|
||||
useShapeBlurCache(shapeRef, 0, [
|
||||
obj.width,
|
||||
obj.fill,
|
||||
obj.fillType,
|
||||
obj.gradient,
|
||||
obj.stroke,
|
||||
actualStrokeWidth,
|
||||
obj.blur,
|
||||
]);
|
||||
|
||||
// برای نمایش انتخاب: اگر strokeWidth واقعی > 0 است، از آن استفاده کن، وگرنه stroke را برای انتخاب نمایش بده
|
||||
@@ -40,9 +44,9 @@ const CircleShape = ({ obj, isSelected, onSelect, onUpdate, draggable }: ShapePr
|
||||
? (hasStroke ? actualStrokeWidth : 3)
|
||||
: (isMask && showGuide ? 2 : actualStrokeWidth);
|
||||
const diameter = obj.width || 100;
|
||||
const gradientProps = isMask
|
||||
? {}
|
||||
: getKonvaGradientProps(obj.fillType, obj.gradient, diameter, diameter, "centered");
|
||||
const gradientProps = isMask || blurRadius > 0
|
||||
? {}
|
||||
: getKonvaGradientProps(obj.fillType, obj.gradient, diameter, diameter, "centered");
|
||||
|
||||
return (
|
||||
<Circle
|
||||
@@ -52,7 +56,8 @@ const CircleShape = ({ obj, isSelected, onSelect, onUpdate, draggable }: ShapePr
|
||||
x={obj.x}
|
||||
y={obj.y}
|
||||
radius={(obj.width || 50) / 2}
|
||||
fill={isMask ? "transparent" : obj.fill}
|
||||
// When blur is enabled, tint is rendered by BlurBackdropLayer.
|
||||
fill={isMask ? "transparent" : blurRadius > 0 ? blurHitFill : (obj.fill ?? "#000000")}
|
||||
{...gradientProps}
|
||||
stroke={displayStroke}
|
||||
strokeWidth={displayStrokeWidth}
|
||||
|
||||
@@ -3,7 +3,8 @@ import { Rect } from "react-konva";
|
||||
import Konva from "konva";
|
||||
import type { ShapeProps } from "./types";
|
||||
import { getKonvaGradientProps } from "../../utils/gradient";
|
||||
import { getKonvaBlurProps, useShapeBlurCache } from "../../utils/shapeBlur";
|
||||
import { getColorWithOpacity } from "../../utils/colorOpacity";
|
||||
import { useShapeBlurCache } from "../../utils/shapeBlur";
|
||||
|
||||
const RectangleShape = ({ obj, isSelected, onSelect, onUpdate, draggable }: ShapeProps) => {
|
||||
const shapeRef = useRef<Konva.Rect>(null);
|
||||
@@ -16,9 +17,13 @@ const RectangleShape = ({ obj, isSelected, onSelect, onUpdate, draggable }: Shap
|
||||
const actualStrokeWidth = obj.strokeWidth ?? 0;
|
||||
const hasStroke = actualStrokeWidth > 0;
|
||||
const cornerRadius = Math.max(0, obj.borderRadius ?? 0);
|
||||
const blurProps = isMask ? {} : getKonvaBlurProps(obj.blur);
|
||||
const blurRadius = obj.blur ?? 0;
|
||||
const blurHitFill = blurRadius > 0 ? getColorWithOpacity(obj.fill ?? "#000000", 0.5) : undefined;
|
||||
// Editor blur is implemented via backdrop-filter (see BlurBackdropLayer),
|
||||
// so we intentionally do not apply Konva blur filters here.
|
||||
const blurProps = {};
|
||||
|
||||
useShapeBlurCache(shapeRef, isMask ? 0 : obj.blur, [
|
||||
useShapeBlurCache(shapeRef, 0, [
|
||||
obj.width,
|
||||
obj.height,
|
||||
cornerRadius,
|
||||
@@ -27,7 +32,6 @@ const RectangleShape = ({ obj, isSelected, onSelect, onUpdate, draggable }: Shap
|
||||
obj.gradient,
|
||||
obj.stroke,
|
||||
actualStrokeWidth,
|
||||
obj.blur,
|
||||
]);
|
||||
|
||||
// برای نمایش انتخاب: اگر strokeWidth واقعی > 0 است، از آن استفاده کن، وگرنه stroke را برای انتخاب نمایش بده
|
||||
@@ -42,7 +46,7 @@ const RectangleShape = ({ obj, isSelected, onSelect, onUpdate, draggable }: Shap
|
||||
const displayStrokeWidth = isSelected
|
||||
? (hasStroke ? actualStrokeWidth : 3)
|
||||
: (isMask && showGuide ? 2 : actualStrokeWidth);
|
||||
const gradientProps = isMask
|
||||
const gradientProps = isMask || blurRadius > 0
|
||||
? {}
|
||||
: getKonvaGradientProps(
|
||||
obj.fillType,
|
||||
@@ -62,7 +66,9 @@ const RectangleShape = ({ obj, isSelected, onSelect, onUpdate, draggable }: Shap
|
||||
width={obj.width || 100}
|
||||
height={obj.height || 100}
|
||||
cornerRadius={cornerRadius}
|
||||
fill={isMask ? "transparent" : obj.fill}
|
||||
// When blur is enabled, visual tint is rendered by BlurBackdropLayer.
|
||||
// Use a tiny non-zero alpha so Konva hit-detection still works for dragging.
|
||||
fill={isMask ? "transparent" : blurRadius > 0 ? blurHitFill : (obj.fill ?? "#000000")}
|
||||
{...gradientProps}
|
||||
stroke={displayStroke}
|
||||
strokeWidth={displayStrokeWidth}
|
||||
|
||||
@@ -3,7 +3,8 @@ import { RegularPolygon } from "react-konva";
|
||||
import Konva from "konva";
|
||||
import type { ShapeProps } from "./types";
|
||||
import { getKonvaGradientProps } from "../../utils/gradient";
|
||||
import { getKonvaBlurProps, useShapeBlurCache } from "../../utils/shapeBlur";
|
||||
import { getColorWithOpacity } from "../../utils/colorOpacity";
|
||||
import { useShapeBlurCache } from "../../utils/shapeBlur";
|
||||
|
||||
const TriangleShape = ({ obj, isSelected, onSelect, onUpdate, draggable }: ShapeProps) => {
|
||||
const shapeRef = useRef<Konva.RegularPolygon>(null);
|
||||
@@ -16,17 +17,20 @@ const TriangleShape = ({ obj, isSelected, onSelect, onUpdate, draggable }: Shape
|
||||
|
||||
const actualStrokeWidth = obj.strokeWidth ?? 0;
|
||||
const hasStroke = actualStrokeWidth > 0;
|
||||
const blurProps = isMask ? {} : getKonvaBlurProps(obj.blur);
|
||||
const blurRadius = obj.blur ?? 0;
|
||||
const blurHitFill = blurRadius > 0 ? getColorWithOpacity(obj.fill ?? "#000000", 0.5) : undefined;
|
||||
// Editor blur is implemented via backdrop-filter (see BlurBackdropLayer).
|
||||
// Avoid applying Konva blur filters on the element itself.
|
||||
const blurProps = {};
|
||||
|
||||
useShapeBlurCache(shapeRef, isMask ? 0 : obj.blur, [
|
||||
useShapeBlurCache(shapeRef, 0, [
|
||||
obj.width,
|
||||
obj.height,
|
||||
obj.fill,
|
||||
obj.fillType,
|
||||
obj.gradient,
|
||||
obj.stroke,
|
||||
actualStrokeWidth,
|
||||
obj.blur,
|
||||
obj.height,
|
||||
]);
|
||||
|
||||
// برای نمایش انتخاب: اگر strokeWidth واقعی > 0 است، از آن استفاده کن، وگرنه stroke را برای انتخاب نمایش بده
|
||||
@@ -41,14 +45,14 @@ const TriangleShape = ({ obj, isSelected, onSelect, onUpdate, draggable }: Shape
|
||||
const displayStrokeWidth = isSelected
|
||||
? (hasStroke ? actualStrokeWidth : 3)
|
||||
: (isMask && showGuide ? 2 : actualStrokeWidth);
|
||||
const gradientProps = isMask
|
||||
? {}
|
||||
: getKonvaGradientProps(
|
||||
obj.fillType,
|
||||
obj.gradient,
|
||||
obj.width || 100,
|
||||
obj.height || 100,
|
||||
"centered",
|
||||
const gradientProps = isMask || blurRadius > 0
|
||||
? {}
|
||||
: getKonvaGradientProps(
|
||||
obj.fillType,
|
||||
obj.gradient,
|
||||
obj.width || 100,
|
||||
obj.height || 100,
|
||||
"centered",
|
||||
);
|
||||
|
||||
return (
|
||||
@@ -60,7 +64,8 @@ const TriangleShape = ({ obj, isSelected, onSelect, onUpdate, draggable }: Shape
|
||||
y={obj.y + (obj.height || 100) / 2}
|
||||
sides={3}
|
||||
radius={radius}
|
||||
fill={isMask ? "transparent" : obj.fill}
|
||||
// When blur is enabled, tint is rendered by BlurBackdropLayer.
|
||||
fill={isMask ? "transparent" : blurRadius > 0 ? blurHitFill : (obj.fill ?? "#000000")}
|
||||
{...gradientProps}
|
||||
stroke={displayStroke}
|
||||
strokeWidth={displayStrokeWidth}
|
||||
|
||||
Reference in New Issue
Block a user