diff --git a/packages/shared/src/components/fields/RichTextEditor/RichTextToolbar.tsx b/packages/shared/src/components/fields/RichTextEditor/RichTextToolbar.tsx index c6c43ac4763..f84fb14c74f 100644 --- a/packages/shared/src/components/fields/RichTextEditor/RichTextToolbar.tsx +++ b/packages/shared/src/components/fields/RichTextEditor/RichTextToolbar.tsx @@ -1,7 +1,12 @@ +import classNames from 'classnames'; import type { ReactElement, ReactNode, Ref } from 'react'; import React, { useState, useCallback, + useEffect, + useLayoutEffect, + useMemo, + useRef, forwardRef, useImperativeHandle, } from 'react'; @@ -10,35 +15,66 @@ import type { Editor } from '@tiptap/react'; import { getMarkRange } from '@tiptap/core'; import { Button, ButtonSize, ButtonVariant } from '../../buttons/Button'; import { + ArrowIcon, BoldIcon, - ItalicIcon, BulletListIcon, + ItalicIcon, NumberedListIcon, - UndoIcon, RedoIcon, + UndoIcon, } from '../../icons'; import { LinkIcon } from '../../icons/Link'; import { Tooltip } from '../../tooltip/Tooltip'; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, +} from '../../dropdown/DropdownMenu'; import { LinkModal } from './LinkModal'; export interface RichTextToolbarProps { editor: Editor; onLinkAdd: (url: string, label?: string) => void; + leadingActions?: ReactNode; inlineActions?: ReactNode; rightActions?: ReactNode; allowBlockFormatting?: boolean; + position?: 'top' | 'bottom'; + className?: string; + hideInlineLink?: boolean; } export interface RichTextToolbarRef { openLinkModal: () => void; } +interface ToolbarItem { + id: string; + tooltip: string; + label: string; + icon: ReactElement; + isActive: boolean; + onClick: () => void; + disabled?: boolean; + priority: number; + group: string; +} + +const ToolbarDivider = (): ReactElement => ( + +); + interface ToolbarButtonProps { tooltip: string; icon: ReactElement; isActive: boolean; onClick: () => void; disabled?: boolean; + alwaysVisible?: boolean; } const ToolbarButton = ({ @@ -47,8 +83,9 @@ const ToolbarButton = ({ isActive, onClick, disabled = false, + alwaysVisible = false, }: ToolbarButtonProps): ReactElement | null => { - if (disabled) { + if (disabled && !alwaysVisible) { return null; } @@ -64,20 +101,75 @@ const ToolbarButton = ({ })} pressed={isActive} onClick={onClick} + onMouseDown={(event: React.MouseEvent) => event.preventDefault()} + disabled={disabled} type="button" - className="leading-none" + className="shrink-0 leading-none" /> ); }; +interface OverflowMenuProps { + items: ToolbarItem[]; +} + +const OverflowMenu = ({ items }: OverflowMenuProps): ReactElement | null => { + const [open, setOpen] = useState(false); + + if (items.length === 0) { + return null; + } + + return ( + + + +