75 lines
1.8 KiB
TypeScript
75 lines
1.8 KiB
TypeScript
"use client";
|
|
|
|
import { useEffect, useState } from "react";
|
|
import { Image } from "react-konva";
|
|
import type Konva from "konva";
|
|
import useImage from "use-image";
|
|
|
|
import {
|
|
applyAdjustmentsToNode,
|
|
buildKonvaFilterList,
|
|
} from "@/lib/image-editor-konva";
|
|
import type { ImageAdjustments, ImageLayer } from "@/lib/image-editor-types";
|
|
|
|
interface ImageBaseLayerProps {
|
|
layer: ImageLayer;
|
|
adjustments: ImageAdjustments;
|
|
interactive?: boolean;
|
|
onSelect: () => void;
|
|
registerNode: (id: string, node: Konva.Node | null) => void;
|
|
}
|
|
|
|
export function ImageBaseLayer({
|
|
layer,
|
|
adjustments,
|
|
interactive = true,
|
|
onSelect,
|
|
registerNode,
|
|
}: ImageBaseLayerProps) {
|
|
const [konvaNode, setKonvaNode] = useState<Konva.Image | null>(null);
|
|
const src =
|
|
typeof layer.props.src === "string" ? layer.props.src : undefined;
|
|
const [image] = useImage(src ?? "", "anonymous");
|
|
const filters = buildKonvaFilterList(adjustments);
|
|
|
|
useEffect(() => {
|
|
if (!konvaNode || !image) return;
|
|
applyAdjustmentsToNode(konvaNode, adjustments, filters);
|
|
}, [konvaNode, image, adjustments, filters]);
|
|
|
|
if (!image) return null;
|
|
|
|
return (
|
|
<Image
|
|
ref={(node) => {
|
|
registerNode(layer.id, node);
|
|
setKonvaNode(node);
|
|
}}
|
|
image={image}
|
|
x={layer.x}
|
|
y={layer.y}
|
|
width={layer.width}
|
|
height={layer.height}
|
|
rotation={layer.rotation}
|
|
opacity={layer.opacity}
|
|
listening={interactive}
|
|
onMouseDown={
|
|
interactive
|
|
? (event) => {
|
|
event.cancelBubble = true;
|
|
onSelect();
|
|
}
|
|
: undefined
|
|
}
|
|
onTap={
|
|
interactive
|
|
? (event) => {
|
|
event.cancelBubble = true;
|
|
onSelect();
|
|
}
|
|
: undefined
|
|
}
|
|
/>
|
|
);
|
|
}
|