071faa482c
纳入 AGC Cargo workspace 的统一 rustfmt 检查与格式化入口 完成项目 TypeScript/Prettier 与 Rust 全量格式化 修复 Pingora expected executable 门禁的空白敏感误报 同步开发运维文档与 AGC skill pack 格式化忽略规则
90 lines
2.0 KiB
TypeScript
90 lines
2.0 KiB
TypeScript
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>
|
||
);
|
||
}
|