Files
Genarrative/src/components/common/PlatformFloatingMenu.tsx
T
kdletters 071faa482c 统一 Rust 与 TypeScript 格式化门禁
纳入 AGC Cargo workspace 的统一 rustfmt 检查与格式化入口

完成项目 TypeScript/Prettier 与 Rust 全量格式化

修复 Pingora expected executable 门禁的空白敏感误报

同步开发运维文档与 AGC skill pack 格式化忽略规则
2026-09-01 16:28:34 +08:00

90 lines
2.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import type {
ButtonHTMLAttributes,
CSSProperties,
HTMLAttributes,
ReactNode,
} from 'react';
/**
* `menu` 承载纯动作集合,子节点必须全是 `PlatformFloatingMenuItem`;
* `options` 承载参数控件(复选框、滑块、选项按钮),它们不是 menuitem,
* 放进 `role="menu"` 既违反 ARIA 子角色约束,也会让读屏进入菜单模式后读不到滑块。
*/
type PlatformFloatingMenuVariant = 'menu' | 'options';
type PlatformFloatingMenuProps = HTMLAttributes<HTMLDivElement> & {
children: ReactNode;
className?: string;
label?: string;
placement?: 'bottom-start' | 'bottom-end' | 'top-start' | 'top-end';
style?: CSSProperties;
variant?: PlatformFloatingMenuVariant;
};
type PlatformFloatingMenuItemProps = Omit<
ButtonHTMLAttributes<HTMLButtonElement>,
'children'
> & {
icon?: ReactNode;
children: ReactNode;
};
/**
* 平台浮层菜单原语。
* 用于卡片角标、画布局部菜单等轻量动作集合,统一 role 与菜单项 chrome。
*/
export function PlatformFloatingMenu({
children,
className,
label,
placement = 'top-end',
style,
variant = 'menu',
onPointerDown,
...divProps
}: PlatformFloatingMenuProps) {
return (
<div
{...divProps}
className={[
'platform-floating-menu',
`platform-floating-menu--${placement}`,
className,
]
.filter(Boolean)
.join(' ')}
role={variant === 'options' ? 'group' : 'menu'}
aria-label={label}
style={style}
onPointerDown={(event) => {
event.stopPropagation();
onPointerDown?.(event);
}}
>
{children}
</div>
);
}
export function PlatformFloatingMenuItem({
icon,
children,
className,
type = 'button',
...buttonProps
}: PlatformFloatingMenuItemProps) {
return (
<button
{...buttonProps}
type={type}
className={['platform-floating-menu__item', className]
.filter(Boolean)
.join(' ')}
role="menuitem"
>
{icon}
<span>{children}</span>
</button>
);
}