Template
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
54 lines
1.2 KiB
TypeScript
54 lines
1.2 KiB
TypeScript
import { type CSSProperties, forwardRef } from "react";
|
||
import { cn } from "@/lib/cn";
|
||
import { getStaticImage } from "@/utils/assets";
|
||
import styles from "./ImageButton.module.css";
|
||
import type { ImageButtonProps } from "./ImageButton.types";
|
||
|
||
// 静态资源 key vs 外部 URL 的解析;未命中时回退原样交给 <img>
|
||
function resolveImage(src: string): string {
|
||
return /^(https?:|data:|blob:)/.test(src) ? src : getStaticImage(src) || src;
|
||
}
|
||
|
||
export const ImageButton = forwardRef<HTMLButtonElement, ImageButtonProps>(
|
||
(
|
||
{
|
||
src,
|
||
alt = "",
|
||
width,
|
||
height,
|
||
hoverScale = 1.05,
|
||
pressScale = 0.95,
|
||
className,
|
||
style,
|
||
...rest
|
||
},
|
||
ref,
|
||
) => {
|
||
const imageSrc = resolveImage(src);
|
||
// hover/按下缩放由 CSS 过渡实现,倍率通过内联变量传入(见 ImageButton.module.css)
|
||
const scaleVars = {
|
||
"--hover-scale": hoverScale,
|
||
"--press-scale": pressScale,
|
||
} as CSSProperties;
|
||
|
||
return (
|
||
<button
|
||
ref={ref}
|
||
type="button"
|
||
className={cn(styles.button, className)}
|
||
style={{ ...scaleVars, width, height, ...style }}
|
||
{...rest}
|
||
>
|
||
<img
|
||
src={imageSrc}
|
||
alt={alt}
|
||
className={styles.image}
|
||
draggable={false}
|
||
/>
|
||
</button>
|
||
);
|
||
},
|
||
);
|
||
|
||
ImageButton.displayName = "ImageButton";
|