fix: use target box flow for canvas scale adjust
This commit is contained in:
parent
aaf3e08dd8
commit
bf8410a6d4
@ -396,22 +396,9 @@ type LocalEditRegionInteractionState = {
|
||||
};
|
||||
|
||||
type CanvasLocalEditOperationMode = "local_edit" | "scale_adjust";
|
||||
type CanvasScaleAdjustPercent = -30 | -20 | -10 | 10 | 20 | 30 | 50 | 100;
|
||||
const CANVAS_SCALE_TARGET_DEFAULT_PERCENT: CanvasScaleAdjustPercent = 50;
|
||||
const CANVAS_SCALE_TARGET_MIN_PERCENT = -80;
|
||||
const CANVAS_SCALE_TARGET_MAX_PERCENT = 200;
|
||||
|
||||
const CANVAS_SCALE_ADJUST_OPTIONS: CanvasScaleAdjustPercent[] = [
|
||||
-30,
|
||||
-20,
|
||||
-10,
|
||||
10,
|
||||
20,
|
||||
30,
|
||||
50,
|
||||
100,
|
||||
];
|
||||
|
||||
function getCanvasScaleAdjustLabel(scalePercent: number) {
|
||||
return scalePercent > 0 ? `放大 ${scalePercent}%` : `缩小 ${Math.abs(scalePercent)}%`;
|
||||
}
|
||||
@ -440,36 +427,6 @@ function getCanvasScaleAdjustRegionPrompt(
|
||||
].join(" ");
|
||||
}
|
||||
|
||||
function scaleCanvasRectAroundCenter(
|
||||
rect: NormalizedCropRect,
|
||||
scalePercent: number
|
||||
): NormalizedCropRect {
|
||||
const requestedScale = Math.max(0.05, 1 + scalePercent / 100);
|
||||
const maxUniformScale = Math.max(
|
||||
0.05,
|
||||
Math.min(
|
||||
rect.width > 0 ? 1 / rect.width : requestedScale,
|
||||
rect.height > 0 ? 1 / rect.height : requestedScale
|
||||
)
|
||||
);
|
||||
const scale = Math.min(requestedScale, maxUniformScale);
|
||||
const width = Math.min(1, rect.width * scale);
|
||||
const height = Math.min(1, rect.height * scale);
|
||||
const centerX = rect.x + rect.width / 2;
|
||||
const centerY = rect.y + rect.height / 2;
|
||||
const x = Math.min(Math.max(centerX - width / 2, 0), Math.max(0, 1 - width));
|
||||
const y = Math.min(Math.max(centerY - height / 2, 0), Math.max(0, 1 - height));
|
||||
|
||||
return { x, y, width, height };
|
||||
}
|
||||
|
||||
function getCanvasScaleTargetRect(
|
||||
region: Pick<LocalEditRegion, "rect" | "targetRect">,
|
||||
fallbackPercent: number
|
||||
): NormalizedCropRect {
|
||||
return region.targetRect || scaleCanvasRectAroundCenter(region.rect, fallbackPercent);
|
||||
}
|
||||
|
||||
function deriveCanvasScalePercentFromRects(
|
||||
sourceRect: NormalizedCropRect,
|
||||
targetRect: NormalizedCropRect | null | undefined
|
||||
@ -1612,8 +1569,6 @@ export function ImageNode({
|
||||
const [localEditMode, setLocalEditMode] = useState(false);
|
||||
const [localEditOperationMode, setLocalEditOperationMode] =
|
||||
useState<CanvasLocalEditOperationMode>("local_edit");
|
||||
const [selectedLocalEditScalePercent, setSelectedLocalEditScalePercent] =
|
||||
useState<CanvasScaleAdjustPercent | null>(null);
|
||||
const [localEditRegions, setLocalEditRegions] = useState<LocalEditRegion[]>(
|
||||
() => getLocalEditRegionsFromMetadata(data.metadata)
|
||||
);
|
||||
@ -1625,6 +1580,8 @@ export function ImageNode({
|
||||
useState<BoxCutoutPoint | null>(null);
|
||||
const [localEditDragEnd, setLocalEditDragEnd] =
|
||||
useState<BoxCutoutPoint | null>(null);
|
||||
const [localEditDrawingTargetRegionId, setLocalEditDrawingTargetRegionId] =
|
||||
useState<string | null>(null);
|
||||
const [localEditRegionInteraction, setLocalEditRegionInteraction] =
|
||||
useState<LocalEditRegionInteractionState | null>(null);
|
||||
const [editingLocalEditRegionId, setEditingLocalEditRegionId] =
|
||||
@ -2380,23 +2337,18 @@ export function ImageNode({
|
||||
if (!boxCutoutMetrics || localEditOperationMode !== "scale_adjust") {
|
||||
return [];
|
||||
}
|
||||
const fallbackPercent =
|
||||
selectedLocalEditScalePercent || CANVAS_SCALE_TARGET_DEFAULT_PERCENT;
|
||||
return localEditRegions.map((region) => {
|
||||
const targetRect = getCanvasScaleTargetRect(region, fallbackPercent);
|
||||
return {
|
||||
region,
|
||||
targetRect,
|
||||
scalePercent: deriveCanvasScalePercentFromRects(region.rect, targetRect),
|
||||
style: getNormalizedRectOverlayStyle(targetRect, boxCutoutMetrics),
|
||||
};
|
||||
});
|
||||
}, [
|
||||
boxCutoutMetrics,
|
||||
localEditOperationMode,
|
||||
localEditRegions,
|
||||
selectedLocalEditScalePercent,
|
||||
]);
|
||||
return localEditRegions
|
||||
.filter((region) => region.targetRect)
|
||||
.map((region) => {
|
||||
const targetRect = region.targetRect as NormalizedCropRect;
|
||||
return {
|
||||
region,
|
||||
targetRect,
|
||||
scalePercent: deriveCanvasScalePercentFromRects(region.rect, targetRect),
|
||||
style: getNormalizedRectOverlayStyle(targetRect, boxCutoutMetrics),
|
||||
};
|
||||
});
|
||||
}, [boxCutoutMetrics, localEditOperationMode, localEditRegions]);
|
||||
const localEditPromptInlineOverlays = useMemo(() => {
|
||||
if (!localEditMode || !boxCutoutMetrics) {
|
||||
return [];
|
||||
@ -2558,10 +2510,10 @@ export function ImageNode({
|
||||
const resetLocalEditState = useCallback(() => {
|
||||
setLocalEditMode(false);
|
||||
setLocalEditOperationMode("local_edit");
|
||||
setSelectedLocalEditScalePercent(null);
|
||||
setIsLocalEditDrawing(false);
|
||||
setLocalEditDragStart(null);
|
||||
setLocalEditDragEnd(null);
|
||||
setLocalEditDrawingTargetRegionId(null);
|
||||
setLocalEditRegionInteraction(null);
|
||||
setEditingLocalEditRegionId(null);
|
||||
setUploadingLocalEditReferenceRegionId(null);
|
||||
@ -3525,11 +3477,9 @@ export function ImageNode({
|
||||
resetBoxCutoutState();
|
||||
setLocalEditRegions(getLocalEditRegionsFromMetadata(data.metadata));
|
||||
setLocalEditOperationMode(operationMode);
|
||||
setSelectedLocalEditScalePercent(
|
||||
operationMode === "scale_adjust" ? CANVAS_SCALE_TARGET_DEFAULT_PERCENT : null
|
||||
);
|
||||
setLocalEditDragStart(null);
|
||||
setLocalEditDragEnd(null);
|
||||
setLocalEditDrawingTargetRegionId(null);
|
||||
setIsLocalEditDrawing(false);
|
||||
setLocalEditMode(true);
|
||||
window.requestAnimationFrame(() => {
|
||||
@ -3537,7 +3487,7 @@ export function ImageNode({
|
||||
});
|
||||
toast.info(
|
||||
operationMode === "scale_adjust"
|
||||
? "先框选要调整比例的主体,再拖动青色目标框调整放大后的大小和位置"
|
||||
? "先框选要调整比例的主体,再框选青色目标大小和位置"
|
||||
: "拖拽框选要局部编辑的位置,并在框下方填写提示词"
|
||||
);
|
||||
},
|
||||
@ -3560,7 +3510,11 @@ export function ImageNode({
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
if (localEditRegions.length >= LOCAL_EDIT_MAX_REGIONS) {
|
||||
const pendingTargetRegion =
|
||||
localEditOperationMode === "scale_adjust"
|
||||
? localEditRegions.find((region) => !region.targetRect)
|
||||
: null;
|
||||
if (!pendingTargetRegion && localEditRegions.length >= LOCAL_EDIT_MAX_REGIONS) {
|
||||
toast.info(`局部编辑最多支持 ${LOCAL_EDIT_MAX_REGIONS} 个区域`);
|
||||
return;
|
||||
}
|
||||
@ -3572,6 +3526,7 @@ export function ImageNode({
|
||||
if (!pointerResult?.insideImage) return;
|
||||
|
||||
setEditingLocalEditRegionId(null);
|
||||
setLocalEditDrawingTargetRegionId(pendingTargetRegion?.id || null);
|
||||
setLocalEditDragStart(pointerResult.point);
|
||||
setLocalEditDragEnd(pointerResult.point);
|
||||
setIsLocalEditDrawing(true);
|
||||
@ -3582,6 +3537,8 @@ export function ImageNode({
|
||||
isProcessing,
|
||||
isSubmittingLocalEdit,
|
||||
localEditMode,
|
||||
localEditOperationMode,
|
||||
localEditRegions,
|
||||
localEditRegions.length,
|
||||
]
|
||||
);
|
||||
@ -3616,6 +3573,7 @@ export function ImageNode({
|
||||
setIsLocalEditDrawing(false);
|
||||
setLocalEditDragStart(null);
|
||||
setLocalEditDragEnd(null);
|
||||
setLocalEditDrawingTargetRegionId(null);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -3631,29 +3589,48 @@ export function ImageNode({
|
||||
nextWidthPx >= LOCAL_EDIT_MIN_EDGE_PX &&
|
||||
nextHeightPx >= LOCAL_EDIT_MIN_EDGE_PX
|
||||
) {
|
||||
if (localEditDrawingTargetRegionId) {
|
||||
const nextRegions = reindexLocalEditRegions(
|
||||
localEditRegions.map((region) => {
|
||||
if (region.id !== localEditDrawingTargetRegionId) return region;
|
||||
const scalePercent = deriveCanvasScalePercentFromRects(
|
||||
region.rect,
|
||||
nextRect
|
||||
);
|
||||
return {
|
||||
...region,
|
||||
targetRect: nextRect,
|
||||
prompt: getCanvasScaleAdjustRegionPrompt(scalePercent, true),
|
||||
};
|
||||
})
|
||||
);
|
||||
commitLocalEditRegions(nextRegions);
|
||||
toast.info("已设置青色目标框,可拖动它继续调整大小和位置");
|
||||
setLocalEditDragStart(null);
|
||||
setLocalEditDragEnd(null);
|
||||
setLocalEditDrawingTargetRegionId(null);
|
||||
setIsLocalEditDrawing(false);
|
||||
return;
|
||||
}
|
||||
|
||||
const isScaleAdjustMode = localEditOperationMode === "scale_adjust";
|
||||
const scalePercent =
|
||||
selectedLocalEditScalePercent || CANVAS_SCALE_TARGET_DEFAULT_PERCENT;
|
||||
const targetRect = isScaleAdjustMode
|
||||
? scaleCanvasRectAroundCenter(nextRect, scalePercent)
|
||||
: undefined;
|
||||
const nextRegion: LocalEditRegion = {
|
||||
id: createLocalEditRegionId(),
|
||||
index: localEditRegions.length + 1,
|
||||
color:
|
||||
LOCAL_EDIT_COLORS[localEditRegions.length % LOCAL_EDIT_COLORS.length],
|
||||
prompt: isScaleAdjustMode
|
||||
? getCanvasScaleAdjustRegionPrompt(scalePercent, true)
|
||||
? "比例调整"
|
||||
: "",
|
||||
rect: nextRect,
|
||||
...(targetRect ? { targetRect } : {}),
|
||||
referenceImages: [],
|
||||
createdAt: Date.now(),
|
||||
};
|
||||
commitLocalEditRegions([...localEditRegions, nextRegion]);
|
||||
setEditingLocalEditRegionId(isScaleAdjustMode ? null : nextRegion.id);
|
||||
if (isScaleAdjustMode) {
|
||||
toast.info("已生成青色目标框,可拖动它调整放大后的大小和位置");
|
||||
setLocalEditDrawingTargetRegionId(nextRegion.id);
|
||||
toast.info("继续拖拽框选青色目标大小和位置");
|
||||
}
|
||||
} else {
|
||||
toast.info("框选区域太小,请至少拖出 24px 以上的区域");
|
||||
@ -3661,16 +3638,17 @@ export function ImageNode({
|
||||
|
||||
setLocalEditDragStart(null);
|
||||
setLocalEditDragEnd(null);
|
||||
setLocalEditDrawingTargetRegionId(null);
|
||||
setIsLocalEditDrawing(false);
|
||||
},
|
||||
[
|
||||
commitLocalEditRegions,
|
||||
getBoxCutoutPointerPoint,
|
||||
localEditDragStart,
|
||||
localEditDrawingTargetRegionId,
|
||||
localEditMode,
|
||||
localEditOperationMode,
|
||||
localEditRegions,
|
||||
selectedLocalEditScalePercent,
|
||||
]
|
||||
);
|
||||
|
||||
@ -3695,6 +3673,7 @@ export function ImageNode({
|
||||
setIsLocalEditDrawing(false);
|
||||
setLocalEditDragStart(null);
|
||||
setLocalEditDragEnd(null);
|
||||
setLocalEditDrawingTargetRegionId(null);
|
||||
event.currentTarget.releasePointerCapture?.(event.pointerId);
|
||||
},
|
||||
[localEditMode]
|
||||
@ -3711,7 +3690,6 @@ export function ImageNode({
|
||||
localEditRegionsRef.current.map((region) => {
|
||||
if (region.id !== regionId) return region;
|
||||
if (target === "scaleTarget") {
|
||||
setSelectedLocalEditScalePercent(null);
|
||||
const scalePercent = deriveCanvasScalePercentFromRects(
|
||||
region.rect,
|
||||
rect
|
||||
@ -4001,23 +3979,6 @@ export function ImageNode({
|
||||
setEditingLocalEditRegionId(null);
|
||||
}, [commitLocalEditRegions]);
|
||||
|
||||
const applyLocalEditScalePercent = useCallback(
|
||||
(scalePercent: CanvasScaleAdjustPercent) => {
|
||||
setSelectedLocalEditScalePercent(scalePercent);
|
||||
const nextRegions = reindexLocalEditRegions(
|
||||
localEditRegionsRef.current.map((region) => ({
|
||||
...region,
|
||||
targetRect: scaleCanvasRectAroundCenter(region.rect, scalePercent),
|
||||
prompt: getCanvasScaleAdjustRegionPrompt(scalePercent, true),
|
||||
}))
|
||||
);
|
||||
localEditRegionsRef.current = nextRegions;
|
||||
setLocalEditRegions(nextRegions);
|
||||
commitLocalEditRegions(nextRegions);
|
||||
},
|
||||
[commitLocalEditRegions]
|
||||
);
|
||||
|
||||
const handleSubmitLocalEdit = useCallback(async () => {
|
||||
if (!data.src) {
|
||||
toast.error("请先上传图片");
|
||||
@ -4033,19 +3994,15 @@ export function ImageNode({
|
||||
}
|
||||
|
||||
const isScaleAdjustMode = localEditOperationMode === "scale_adjust";
|
||||
const scaleFallbackPercent =
|
||||
selectedLocalEditScalePercent || CANVAS_SCALE_TARGET_DEFAULT_PERCENT;
|
||||
const validRegions = reindexLocalEditRegions(
|
||||
localEditRegions.map((region) => {
|
||||
if (isScaleAdjustMode) {
|
||||
const targetRect = getCanvasScaleTargetRect(region, scaleFallbackPercent);
|
||||
const regionScalePercent = deriveCanvasScalePercentFromRects(
|
||||
region.rect,
|
||||
targetRect
|
||||
region.targetRect
|
||||
);
|
||||
return {
|
||||
...region,
|
||||
targetRect,
|
||||
prompt: getCanvasScaleAdjustRegionPrompt(regionScalePercent, true),
|
||||
};
|
||||
}
|
||||
@ -4063,6 +4020,11 @@ export function ImageNode({
|
||||
return;
|
||||
}
|
||||
if (isScaleAdjustMode) {
|
||||
const missingTargetRegion = validRegions.find((region) => !region.targetRect);
|
||||
if (missingTargetRegion) {
|
||||
toast.error(`请为区域 ${missingTargetRegion.index} 框选青色目标框`);
|
||||
return;
|
||||
}
|
||||
const unchangedRegion = validRegions.find((region) => {
|
||||
const regionScalePercent = deriveCanvasScalePercentFromRects(
|
||||
region.rect,
|
||||
@ -4282,7 +4244,6 @@ export function ImageNode({
|
||||
node.size.width,
|
||||
resetLocalEditState,
|
||||
selectNode,
|
||||
selectedLocalEditScalePercent,
|
||||
updateNode,
|
||||
]);
|
||||
|
||||
@ -8675,24 +8636,32 @@ export function ImageNode({
|
||||
setEditingLocalEditRegionId(region.id);
|
||||
}
|
||||
}}
|
||||
title={
|
||||
localEditOperationMode === "scale_adjust"
|
||||
? selectedLocalEditScalePercent
|
||||
? getCanvasScaleAdjustLabel(selectedLocalEditScalePercent)
|
||||
: "请选择比例"
|
||||
: region.prompt
|
||||
}
|
||||
type="button"
|
||||
>
|
||||
{localEditOperationMode === "scale_adjust"
|
||||
? `${region.index}. ${
|
||||
selectedLocalEditScalePercent
|
||||
? getCanvasScaleAdjustLabel(
|
||||
selectedLocalEditScalePercent
|
||||
)
|
||||
: "请选择比例"
|
||||
}`
|
||||
: `${region.index}. ${region.prompt}`}
|
||||
title={
|
||||
localEditOperationMode === "scale_adjust"
|
||||
? region.targetRect
|
||||
? getCanvasScaleAdjustLabel(
|
||||
deriveCanvasScalePercentFromRects(
|
||||
region.rect,
|
||||
region.targetRect
|
||||
)
|
||||
)
|
||||
: "请框选青色目标框"
|
||||
: region.prompt
|
||||
}
|
||||
type="button"
|
||||
>
|
||||
{localEditOperationMode === "scale_adjust"
|
||||
? `${region.index}. ${
|
||||
region.targetRect
|
||||
? getCanvasScaleAdjustLabel(
|
||||
deriveCanvasScalePercentFromRects(
|
||||
region.rect,
|
||||
region.targetRect
|
||||
)
|
||||
)
|
||||
: "请框选目标框"
|
||||
}`
|
||||
: `${region.index}. ${region.prompt}`}
|
||||
</button>
|
||||
)}
|
||||
<input
|
||||
@ -8836,7 +8805,12 @@ export function ImageNode({
|
||||
: null}
|
||||
{localEditDraftRectStyle ? (
|
||||
<div
|
||||
className="pointer-events-none absolute z-[162] rounded-none border-[1.5px] border-[#27a8ff] bg-transparent shadow-none"
|
||||
className={cn(
|
||||
"pointer-events-none absolute z-[162] rounded-none border-[1.5px] bg-transparent shadow-none",
|
||||
localEditDrawingTargetRegionId
|
||||
? "border-dashed border-cyan-300"
|
||||
: "border-[#27a8ff]"
|
||||
)}
|
||||
style={{
|
||||
left: localEditDraftRectStyle.left,
|
||||
top: localEditDraftRectStyle.top,
|
||||
@ -9294,11 +9268,10 @@ export function ImageNode({
|
||||
? "bg-white text-slate-950 shadow-sm dark:bg-white dark:text-slate-950"
|
||||
: "text-slate-500 hover:bg-white/70 hover:text-slate-900 dark:text-slate-300 dark:hover:bg-white/10 dark:hover:text-white"
|
||||
)}
|
||||
disabled={isSubmittingLocalEdit}
|
||||
onClick={() => {
|
||||
setLocalEditOperationMode("local_edit");
|
||||
setSelectedLocalEditScalePercent(null);
|
||||
}}
|
||||
disabled={isSubmittingLocalEdit}
|
||||
onClick={() => {
|
||||
setLocalEditOperationMode("local_edit");
|
||||
}}
|
||||
type="button"
|
||||
variant="ghost"
|
||||
>
|
||||
@ -9311,14 +9284,11 @@ export function ImageNode({
|
||||
? "bg-white text-slate-950 shadow-sm dark:bg-white dark:text-slate-950"
|
||||
: "text-slate-500 hover:bg-white/70 hover:text-slate-900 dark:text-slate-300 dark:hover:bg-white/10 dark:hover:text-white"
|
||||
)}
|
||||
disabled={isSubmittingLocalEdit}
|
||||
onClick={() => {
|
||||
setLocalEditOperationMode("scale_adjust");
|
||||
if (!selectedLocalEditScalePercent) {
|
||||
applyLocalEditScalePercent(CANVAS_SCALE_TARGET_DEFAULT_PERCENT);
|
||||
}
|
||||
setEditingLocalEditRegionId(null);
|
||||
}}
|
||||
disabled={isSubmittingLocalEdit}
|
||||
onClick={() => {
|
||||
setLocalEditOperationMode("scale_adjust");
|
||||
setEditingLocalEditRegionId(null);
|
||||
}}
|
||||
type="button"
|
||||
variant="ghost"
|
||||
>
|
||||
@ -9328,43 +9298,23 @@ export function ImageNode({
|
||||
|
||||
<div className="mx-1 h-6 w-px bg-slate-200 dark:bg-slate-700" />
|
||||
|
||||
{localEditOperationMode === "scale_adjust" ? (
|
||||
<div className="inline-flex shrink-0 items-center gap-1">
|
||||
<span className="hidden whitespace-nowrap px-1 text-[12px] font-medium text-slate-500 dark:text-slate-300 lg:inline">
|
||||
拖动青色目标框
|
||||
</span>
|
||||
{CANVAS_SCALE_ADJUST_OPTIONS.map((option) => {
|
||||
const active = selectedLocalEditScalePercent === option;
|
||||
const Icon = option > 0 ? Maximize2 : Minimize2;
|
||||
return (
|
||||
<Button
|
||||
className={cn(
|
||||
"inline-flex h-9 items-center justify-center rounded-xl border px-2 text-[12px] font-semibold",
|
||||
active
|
||||
? "border-emerald-300 bg-emerald-50 text-emerald-700 dark:border-emerald-300/45 dark:bg-emerald-400/16 dark:text-emerald-100"
|
||||
: "border-slate-200 bg-white text-slate-600 hover:bg-slate-50 hover:text-slate-950 dark:border-white/12 dark:bg-zinc-900 dark:text-slate-200 dark:hover:bg-white/10"
|
||||
)}
|
||||
disabled={isSubmittingLocalEdit}
|
||||
key={option}
|
||||
onClick={() => applyLocalEditScalePercent(option)}
|
||||
title={getCanvasScaleAdjustLabel(option)}
|
||||
type="button"
|
||||
variant="ghost"
|
||||
>
|
||||
<Icon className="mr-1 h-3.5 w-3.5 shrink-0" />
|
||||
{option > 0 ? `+${option}%` : `${option}%`}
|
||||
</Button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
) : null}
|
||||
{localEditOperationMode === "scale_adjust" ? (
|
||||
<div className="inline-flex h-10 shrink-0 items-center gap-2 rounded-xl border border-cyan-300/35 bg-cyan-50 px-3 text-[12px] font-semibold text-cyan-800 dark:border-cyan-300/25 dark:bg-cyan-400/10 dark:text-cyan-100">
|
||||
<Maximize2 className="h-3.5 w-3.5 shrink-0" />
|
||||
<span className="whitespace-nowrap">
|
||||
先框主体,再框目标大小和位置
|
||||
</span>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
<Button
|
||||
className="mr-1 inline-flex h-10 shrink-0 items-center gap-1.5 whitespace-nowrap rounded-xl bg-slate-950 px-3 font-semibold text-[13px] text-white hover:bg-slate-800 hover:text-white disabled:bg-slate-300 disabled:text-slate-500 dark:border dark:border-white/14 dark:bg-black dark:text-white dark:disabled:border-transparent dark:disabled:bg-slate-700 dark:disabled:text-slate-400 dark:hover:bg-zinc-900"
|
||||
disabled={
|
||||
isSubmittingLocalEdit ||
|
||||
localEditRegions.length === 0
|
||||
}
|
||||
disabled={
|
||||
isSubmittingLocalEdit ||
|
||||
localEditRegions.length === 0 ||
|
||||
(localEditOperationMode === "scale_adjust" &&
|
||||
localEditRegions.some((region) => !region.targetRect))
|
||||
}
|
||||
onClick={() => void handleSubmitLocalEdit()}
|
||||
title={
|
||||
localEditOperationMode === "scale_adjust"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user