新增 PlatformUiKit 通用弹窗、按钮、状态、空态、媒体、表单和标签等公共组件 迁移结果页、创作工作台、认证入口、RPG 暗色面板和运行态弹窗的重复 UI chrome 补充组件测试、页面回归测试、技术文档和 Hermes 共享决策记录
90 lines
2.2 KiB
TypeScript
90 lines
2.2 KiB
TypeScript
import type {
|
|
ButtonHTMLAttributes,
|
|
LabelHTMLAttributes,
|
|
ReactNode,
|
|
} from 'react';
|
|
|
|
type PlatformIconButtonBaseProps = {
|
|
label: string;
|
|
icon: ReactNode;
|
|
children?: ReactNode;
|
|
variant?: 'platformIcon' | 'surfaceFloating' | 'darkMini';
|
|
};
|
|
|
|
type PlatformIconButtonButtonProps = Omit<
|
|
ButtonHTMLAttributes<HTMLButtonElement>,
|
|
'aria-label' | 'children'
|
|
> &
|
|
PlatformIconButtonBaseProps & {
|
|
asChild?: false;
|
|
};
|
|
|
|
type PlatformIconButtonLabelProps = Omit<
|
|
LabelHTMLAttributes<HTMLLabelElement>,
|
|
'aria-label' | 'children'
|
|
> &
|
|
PlatformIconButtonBaseProps & {
|
|
asChild: 'label';
|
|
};
|
|
|
|
type PlatformIconButtonProps =
|
|
| PlatformIconButtonButtonProps
|
|
| PlatformIconButtonLabelProps;
|
|
|
|
/**
|
|
* 平台通用图标动作按钮。
|
|
* 统一承接纯图标动作、图标上传 label 和带短标签的浮动图标动作。
|
|
*/
|
|
export function PlatformIconButton({
|
|
label,
|
|
icon,
|
|
children,
|
|
variant = 'platformIcon',
|
|
title,
|
|
className,
|
|
asChild,
|
|
...actionProps
|
|
}: PlatformIconButtonProps) {
|
|
const variantClassName = {
|
|
platformIcon: 'platform-icon-button',
|
|
surfaceFloating:
|
|
'inline-flex items-center justify-center rounded-full border border-white/80 bg-white/94 text-[var(--platform-text-strong)] shadow-sm backdrop-blur transition hover:text-[var(--platform-accent)] disabled:cursor-not-allowed disabled:opacity-55',
|
|
darkMini:
|
|
'inline-flex items-center justify-center rounded-full border border-white/16 bg-black/55 text-white transition-colors hover:bg-black/70 disabled:cursor-not-allowed disabled:opacity-55',
|
|
}[variant];
|
|
|
|
const actionClassName = [variantClassName, className]
|
|
.filter(Boolean)
|
|
.join(' ');
|
|
|
|
if (asChild === 'label') {
|
|
return (
|
|
<label
|
|
{...(actionProps as LabelHTMLAttributes<HTMLLabelElement>)}
|
|
title={title}
|
|
className={actionClassName}
|
|
>
|
|
<span className="sr-only">{label}</span>
|
|
{icon}
|
|
{children}
|
|
</label>
|
|
);
|
|
}
|
|
|
|
const { type = 'button', ...buttonProps } =
|
|
actionProps as ButtonHTMLAttributes<HTMLButtonElement>;
|
|
|
|
return (
|
|
<button
|
|
{...buttonProps}
|
|
type={type}
|
|
aria-label={label}
|
|
title={title}
|
|
className={actionClassName}
|
|
>
|
|
{icon}
|
|
{children}
|
|
</button>
|
|
);
|
|
}
|