03a4410272
主要工作是共享同一套“画布内核与通用 UI 源码”,网站和 Tauri 只分别实现宿主适配层。 --------- Co-authored-by: 段舒康 <kdletters@qq.com> Co-authored-by: kdletters <kdletters@qq.com> Reviewed-on: http://192.168.35.82/git/GenarrativeAI/Genarrative/pulls/136 Co-authored-by: menghao <mh18530625731@163.com> Co-committed-by: menghao <mh18530625731@163.com>
153 lines
3.5 KiB
TypeScript
153 lines
3.5 KiB
TypeScript
import {
|
|
type ButtonHTMLAttributes,
|
|
forwardRef,
|
|
type HTMLAttributes,
|
|
type ReactNode,
|
|
} from 'react';
|
|
|
|
function joinClassNames(...classNames: Array<string | undefined | false>) {
|
|
return classNames.filter(Boolean).join(' ');
|
|
}
|
|
|
|
export type CanvasChromeButtonProps = Omit<
|
|
ButtonHTMLAttributes<HTMLButtonElement>,
|
|
'aria-expanded' | 'aria-label' | 'aria-pressed' | 'children'
|
|
> & {
|
|
label: string;
|
|
icon: ReactNode;
|
|
children?: ReactNode;
|
|
pressed?: boolean;
|
|
expanded?: boolean;
|
|
};
|
|
|
|
/**
|
|
* 画布宿主共享的动作按钮,只承接 chrome、可访问性与原生按钮状态。
|
|
*/
|
|
export const CanvasChromeButton = forwardRef<
|
|
HTMLButtonElement,
|
|
CanvasChromeButtonProps
|
|
>(function CanvasChromeButton(
|
|
{
|
|
label,
|
|
icon,
|
|
children,
|
|
pressed,
|
|
expanded,
|
|
title = label,
|
|
type = 'button',
|
|
className,
|
|
...buttonProps
|
|
},
|
|
ref,
|
|
) {
|
|
const hasVisibleLabel =
|
|
children !== undefined && children !== null && children !== false;
|
|
|
|
return (
|
|
<button
|
|
{...buttonProps}
|
|
ref={ref}
|
|
type={type}
|
|
className={joinClassNames(
|
|
'genarrative-image-canvas__chrome-button',
|
|
hasVisibleLabel &&
|
|
'genarrative-image-canvas__chrome-button--with-label',
|
|
className,
|
|
)}
|
|
aria-label={label}
|
|
aria-pressed={pressed}
|
|
aria-expanded={expanded}
|
|
title={title}
|
|
>
|
|
<span className="genarrative-image-canvas__chrome-button-icon">
|
|
{icon}
|
|
</span>
|
|
{hasVisibleLabel ? (
|
|
<span className="genarrative-image-canvas__chrome-button-label">
|
|
{children}
|
|
</span>
|
|
) : null}
|
|
</button>
|
|
);
|
|
});
|
|
|
|
export type CanvasToolbarProps = Omit<
|
|
HTMLAttributes<HTMLDivElement>,
|
|
'aria-label' | 'children' | 'role'
|
|
> & {
|
|
label: string;
|
|
children: ReactNode;
|
|
surface?: 'plain' | 'floating';
|
|
};
|
|
|
|
/** 画布宿主共享的横向工具栏容器。 */
|
|
export const CanvasToolbar = forwardRef<HTMLDivElement, CanvasToolbarProps>(
|
|
function CanvasToolbar(
|
|
{ label, children, surface = 'plain', className, ...toolbarProps },
|
|
ref,
|
|
) {
|
|
return (
|
|
<div
|
|
{...toolbarProps}
|
|
ref={ref}
|
|
role="toolbar"
|
|
aria-label={label}
|
|
aria-orientation="horizontal"
|
|
className={joinClassNames(
|
|
'genarrative-image-canvas__toolbar',
|
|
`genarrative-image-canvas__toolbar--${surface}`,
|
|
className,
|
|
)}
|
|
>
|
|
{children}
|
|
</div>
|
|
);
|
|
},
|
|
);
|
|
|
|
export type CanvasToolbarGroupProps = HTMLAttributes<HTMLSpanElement> & {
|
|
children: ReactNode;
|
|
};
|
|
|
|
/** 将同类画布动作保持为不可拆散的横向分组。 */
|
|
export const CanvasToolbarGroup = forwardRef<
|
|
HTMLSpanElement,
|
|
CanvasToolbarGroupProps
|
|
>(function CanvasToolbarGroup({ children, className, ...groupProps }, ref) {
|
|
return (
|
|
<span
|
|
{...groupProps}
|
|
ref={ref}
|
|
className={joinClassNames(
|
|
'genarrative-image-canvas__toolbar-group',
|
|
className,
|
|
)}
|
|
>
|
|
{children}
|
|
</span>
|
|
);
|
|
});
|
|
|
|
export type CanvasToolbarDividerProps = Omit<
|
|
HTMLAttributes<HTMLSpanElement>,
|
|
'aria-hidden' | 'children'
|
|
>;
|
|
|
|
/** 纯视觉工具分隔符,不进入无障碍树。 */
|
|
export const CanvasToolbarDivider = forwardRef<
|
|
HTMLSpanElement,
|
|
CanvasToolbarDividerProps
|
|
>(function CanvasToolbarDivider({ className, ...dividerProps }, ref) {
|
|
return (
|
|
<span
|
|
{...dividerProps}
|
|
ref={ref}
|
|
aria-hidden="true"
|
|
className={joinClassNames(
|
|
'genarrative-image-canvas__toolbar-divider',
|
|
className,
|
|
)}
|
|
/>
|
|
);
|
|
});
|