import FocusTrap from 'focus-trap-react';
import {
Badge,
Box,
config,
Icon,
IconButton,
Icons,
IconSrc,
Line,
Menu,
PopOut,
RectCords,
Scroll,
Text,
Tooltip,
TooltipProvider,
toRem,
} from 'folds';
import React, { MouseEventHandler, ReactNode, useState } from 'react';
import { ReactEditor, useSlate } from 'slate-react';
import {
headingLevel,
isAnyMarkActive,
isBlockActive,
isMarkActive,
removeAllMark,
toggleBlock,
toggleMark,
} from './utils';
import * as css from './Editor.css';
import { BlockType, MarkType } from './types';
import { HeadingLevel } from './slate';
import { isMacOS } from '../../utils/user-agent';
import { KeySymbol } from '../../utils/key-symbol';
import { useSetting } from '../../state/hooks/settings';
import { settingsAtom } from '../../state/settings';
import { stopPropagation } from '../../utils/keyboard';
function BtnTooltip({ text, shortCode }: { text: string; shortCode?: string }) {
return (
{text}
{shortCode && (
{shortCode}
)}
);
}
type MarkButtonProps = { format: MarkType; icon: IconSrc; tooltip: ReactNode };
export function MarkButton({ format, icon, tooltip }: MarkButtonProps) {
const editor = useSlate();
const disableInline = isBlockActive(editor, BlockType.CodeBlock);
if (disableInline) {
removeAllMark(editor);
}
const handleClick = () => {
toggleMark(editor, format);
ReactEditor.focus(editor);
};
return (
{(triggerRef) => (
)}
);
}
type BlockButtonProps = {
format: BlockType;
icon: IconSrc;
tooltip: ReactNode;
};
export function BlockButton({ format, icon, tooltip }: BlockButtonProps) {
const editor = useSlate();
const handleClick = () => {
toggleBlock(editor, format, { level: 1 });
ReactEditor.focus(editor);
};
return (
{(triggerRef) => (
)}
);
}
export function HeadingBlockButton() {
const editor = useSlate();
const level = headingLevel(editor);
const [anchor, setAnchor] = useState();
const isActive = isBlockActive(editor, BlockType.Heading);
const modKey = isMacOS() ? KeySymbol.Command : 'Ctrl';
const handleMenuSelect = (selectedLevel: HeadingLevel) => {
setAnchor(undefined);
toggleBlock(editor, BlockType.Heading, { level: selectedLevel });
ReactEditor.focus(editor);
};
const handleMenuOpen: MouseEventHandler = (evt) => {
if (isActive) {
toggleBlock(editor, BlockType.Heading);
return;
}
setAnchor(evt.currentTarget.getBoundingClientRect());
};
return (
setAnchor(undefined),
clickOutsideDeactivates: true,
isKeyForward: (evt: KeyboardEvent) =>
evt.key === 'ArrowDown' || evt.key === 'ArrowRight',
isKeyBackward: (evt: KeyboardEvent) => evt.key === 'ArrowUp' || evt.key === 'ArrowLeft',
escapeDeactivates: stopPropagation,
}}
>
}
>
);
}
type ExitFormattingProps = { tooltip: ReactNode };
export function ExitFormatting({ tooltip }: ExitFormattingProps) {
const editor = useSlate();
const handleClick = () => {
if (isAnyMarkActive(editor)) {
removeAllMark(editor);
} else if (!isBlockActive(editor, BlockType.Paragraph)) {
toggleBlock(editor, BlockType.Paragraph);
}
ReactEditor.focus(editor);
};
return (
{(triggerRef) => (
{`Exit ${KeySymbol.Hyper}`}
)}
);
}
export function Toolbar() {
const editor = useSlate();
const modKey = isMacOS() ? KeySymbol.Command : 'Ctrl';
const disableInline = isBlockActive(editor, BlockType.CodeBlock);
const canEscape = isBlockActive(editor, BlockType.Paragraph)
? isAnyMarkActive(editor)
: ReactEditor.isFocused(editor);
const [isMarkdown, setIsMarkdown] = useSetting(settingsAtom, 'isMarkdown');
return (
<>
}
/>
}
/>
}
/>
}
/>
}
/>
}
/>
>
}
/>
}
/>
}
/>
}
/>
{canEscape && (
<>
}
/>
>
)}
}
delay={500}
>
{(triggerRef) => (
setIsMarkdown(!isMarkdown)}
aria-pressed={isMarkdown}
size="300"
radii="300"
disabled={disableInline || !!isAnyMarkActive(editor)}
>
)}
);
}