ea29887d9c
- 快速编辑支持最多8张额外参考图,并将原图自动作为最后一张参考图提交 - 快速编辑尺寸和模型沿用原图配置,按禁用态参数胶囊展示 - 快速编辑提交前同步改写原图引用为实际图序号 - 快速编辑生成改为创建独立画布生成占位,并支持键盘删除生成中对象 - 对齐生成类面板参考图图标、规范类固定参数和相关文档测试
117 lines
2.9 KiB
TypeScript
117 lines
2.9 KiB
TypeScript
import { type ReactNode, type RefObject } from 'react';
|
|
import { X } from 'lucide-react';
|
|
|
|
type ImageCanvasReferenceSlotTone =
|
|
| 'default'
|
|
| 'spec'
|
|
| 'icon'
|
|
| 'ui'
|
|
| 'character'
|
|
| 'quick-edit'
|
|
| 'video'
|
|
| 'audio';
|
|
|
|
type ImageCanvasReferenceSlotProps = {
|
|
buttonRef?: RefObject<HTMLButtonElement | null>;
|
|
tone?: ImageCanvasReferenceSlotTone;
|
|
className?: string;
|
|
icon: ReactNode;
|
|
label: string;
|
|
ariaLabel: string;
|
|
title?: string;
|
|
imageSrc?: string | null;
|
|
disabled?: boolean;
|
|
isAdd?: boolean;
|
|
onClick?: () => void;
|
|
onRemove?: () => void;
|
|
removeLabel?: string;
|
|
};
|
|
|
|
export function ImageCanvasReferenceSlot({
|
|
buttonRef,
|
|
tone = 'default',
|
|
className,
|
|
icon,
|
|
label,
|
|
ariaLabel,
|
|
title,
|
|
imageSrc,
|
|
disabled = false,
|
|
isAdd = false,
|
|
onClick,
|
|
onRemove,
|
|
removeLabel,
|
|
}: ImageCanvasReferenceSlotProps) {
|
|
const hasPreviewImage = Boolean(imageSrc);
|
|
const slotClassName = [
|
|
'image-canvas-editor__reference-chip',
|
|
`image-canvas-editor__reference-chip--${tone}`,
|
|
hasPreviewImage
|
|
? 'image-canvas-editor__reference-chip--has-image'
|
|
: 'image-canvas-editor__reference-chip--icon-only',
|
|
isAdd ? 'image-canvas-editor__reference-chip--upload' : null,
|
|
className,
|
|
]
|
|
.filter(Boolean)
|
|
.join(' ');
|
|
const slotContent = (
|
|
<>
|
|
<span className="image-canvas-editor__reference-chip-icon">
|
|
{hasPreviewImage ? (
|
|
<img src={imageSrc ?? undefined} alt="" aria-hidden="true" />
|
|
) : (
|
|
icon
|
|
)}
|
|
</span>
|
|
<span className="image-canvas-editor__reference-chip-label">{label}</span>
|
|
{title && title !== label ? (
|
|
<span className="image-canvas-editor__reference-chip-source-label">
|
|
{title}
|
|
</span>
|
|
) : null}
|
|
</>
|
|
);
|
|
return (
|
|
<span className="image-canvas-editor__reference-slot">
|
|
{onClick || buttonRef ? (
|
|
<button
|
|
ref={buttonRef}
|
|
type="button"
|
|
className={slotClassName}
|
|
disabled={disabled}
|
|
aria-label={ariaLabel}
|
|
title={title ?? ariaLabel}
|
|
onClick={onClick}
|
|
>
|
|
{slotContent}
|
|
</button>
|
|
) : (
|
|
<span
|
|
className={slotClassName}
|
|
aria-label={ariaLabel}
|
|
title={title ?? ariaLabel}
|
|
>
|
|
{slotContent}
|
|
</span>
|
|
)}
|
|
{onRemove ? (
|
|
<button
|
|
type="button"
|
|
className="image-canvas-editor__reference-chip-remove"
|
|
disabled={disabled}
|
|
aria-label={removeLabel ?? `删除${ariaLabel}`}
|
|
title="删除"
|
|
onPointerDown={(event) => event.stopPropagation()}
|
|
onClick={(event) => {
|
|
event.preventDefault();
|
|
event.stopPropagation();
|
|
onRemove();
|
|
}}
|
|
>
|
|
<X className="h-3 w-3" aria-hidden="true" />
|
|
</button>
|
|
) : null}
|
|
</span>
|
|
);
|
|
}
|