Skip to content
File

Blob: src/client/components/editor/controllers/toolbar-button.tsx

typescript43 lines
1import { type ReactNode, type Ref } from "react";
2 
3interface ToolbarButtonProps {
4 ref?: Ref<HTMLButtonElement>;
5 active?: boolean;
6 disabled?: boolean;
7 title: string;
8 onActivate: () => void;
9 children: ReactNode;
10}
11 
12// Toolbar buttons live inside Tiptap floating menus (.tiptap-toolbar, .tiptap-link-toolbar, .tiptap-block-menu).
13// They MUST use onMouseDown + preventDefault to keep the editor selection from collapsing on press —
14// onClick fires too late, after the editor has already responded to focus changes.
15export function ToolbarButton({ ref, active, disabled, title, onActivate, children }: ToolbarButtonProps) {
16 return (
17 <button
18 ref={ref}
19 type="button"
20 title={title}
21 aria-label={title}
22 aria-disabled={disabled || undefined}
23 disabled={disabled}
24 className={active ? "is-active" : undefined}
25 onMouseDown={(e) => {
26 e.preventDefault();
27 e.stopPropagation();
28 if (disabled) return;
29 onActivate();
30 }}
31 onClick={(e) => {
32 // Keyboard and assistive-technology activation has no preceding mouse down.
33 if (e.detail !== 0 || disabled) return;
34 e.preventDefault();
35 e.stopPropagation();
36 onActivate();
37 }}
38 >
39 {children}
40 </button>
41 );
42}