Files
Genarrative/src/components/image-editor/ImageCanvasReferenceSlot.tsx
T
menghao e4e3cab559
Project CI / Repository checks (push) Successful in 3m3s
Project CI / Frontend tests (push) Successful in 3m32s
Project CI / Backend tests (push) Successful in 5m45s
Project CI / Native shell tests (push) Successful in 16m17s
修复画布参考图上传删除链路 (#164)
主站规范生成支持多张参考图

修复普通生成参考图删除与提交状态不同步

优化触屏设备删除按钮可达性并补充回归测试

---------

Co-authored-by: kdletters <kdletters@qq.com>
Reviewed-on: http://192.168.35.82/git/GenarrativeAI/Genarrative/pulls/164
Co-authored-by: 孟豪 <mh18530625731@163.com>
Co-committed-by: 孟豪 <mh18530625731@163.com>
2026-08-21 11:55:32 +08:00

132 lines
3.3 KiB
TypeScript

import { X } from 'lucide-react';
import { type ReactNode, type RefObject } from 'react';
import { ResolvedAssetImage } from '../ResolvedAssetImage';
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;
objectKey?: string | null;
disabled?: boolean;
isAdd?: boolean;
onClick?: () => void;
onRemove?: () => void;
removeLabel?: string;
alwaysShowRemove?: boolean;
};
export function ImageCanvasReferenceSlot({
buttonRef,
tone = 'default',
className,
icon,
label,
ariaLabel,
title,
imageSrc,
objectKey,
disabled = false,
isAdd = false,
onClick,
onRemove,
removeLabel,
alwaysShowRemove = false,
}: ImageCanvasReferenceSlotProps) {
const hasPreviewImage = Boolean(imageSrc?.trim() || objectKey?.trim());
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 ? (
<ResolvedAssetImage
src={imageSrc}
objectKey={objectKey}
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${
alwaysShowRemove
? ' image-canvas-editor__reference-chip-remove--always-visible'
: ''
}`}
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>
);
}