Files
Genarrative/src/components/image-editor/ImageCanvasReferenceSlot.tsx
T
kdletters 387a1c26e3 完成全量检查整改
清理已跟踪原始日志与个人本地配置
修复前后端有效门禁、测试和构建问题
补齐生产 Jenkins、SpacetimeDB 本地命令与文档约束
收紧图片编辑器状态、附件与媒体引用测试
排除已下线旧创作入口测试并清理 warning
2026-07-17 16:56:46 +08:00

126 lines
3.1 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;
};
export function ImageCanvasReferenceSlot({
buttonRef,
tone = 'default',
className,
icon,
label,
ariaLabel,
title,
imageSrc,
objectKey,
disabled = false,
isAdd = false,
onClick,
onRemove,
removeLabel,
}: 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"
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>
);
}