Files
omniai-web/src/features/ecommerce/ImageMentionMenu.tsx
T
2026-06-02 12:38:01 +08:00

72 lines
2.4 KiB
TypeScript

export interface MentionImageOption {
id: string;
src: string;
name: string;
label?: string;
}
export function getImageMentionQuery(value: string, selectionStart: number | null | undefined): string | null {
if (selectionStart === null || selectionStart === undefined) return null;
const beforeCursor = value.slice(0, selectionStart);
const match = beforeCursor.match(/(?:^|\s)@([^\s@]*)$/);
return match ? match[1] ?? "" : null;
}
export function insertImageMentionValue(
value: string,
selectionStart: number,
imageName: string,
maxLength: number,
): { value: string; selectionStart: number } {
const beforeCursor = value.slice(0, selectionStart);
const afterCursor = value.slice(selectionStart);
const match = beforeCursor.match(/(?:^|\s)@([^\s@]*)$/);
const mentionStart = match ? beforeCursor.length - match[0].length + (match[0].startsWith("@") ? 0 : 1) : selectionStart;
const mentionText = `@${imageName.trim() || "uploaded-image"} `;
const nextValue = `${value.slice(0, mentionStart)}${mentionText}${afterCursor}`.slice(0, maxLength);
const nextSelectionStart = Math.min(mentionStart + mentionText.length, nextValue.length);
return { value: nextValue, selectionStart: nextSelectionStart };
}
interface ImageMentionMenuProps {
images: MentionImageOption[];
query?: string;
onSelect: (image: MentionImageOption) => void;
}
function ImageMentionMenu({ images, query = "", onSelect }: ImageMentionMenuProps) {
const normalizedQuery = query.trim().toLowerCase();
const visibleImages = normalizedQuery
? images.filter((image) => `${image.label ?? ""} ${image.name}`.toLowerCase().includes(normalizedQuery))
: images;
return (
<div className="image-mention-menu" role="listbox" aria-label="选择上传图片">
{visibleImages.length ? (
visibleImages.map((image) => (
<button
key={image.id}
type="button"
className="image-mention-menu__item"
role="option"
onMouseDown={(event) => {
event.preventDefault();
onSelect(image);
}}
>
<img src={image.src} alt="" />
<span>
<strong>{image.label ?? image.name}</strong>
<em>{image.name}</em>
</span>
</button>
))
) : (
<span className="image-mention-menu__empty"></span>
)}
</div>
);
}
export default ImageMentionMenu;