import React, { ReactElement, FC, ComponentType, useState, useCallback, useEffect, } from 'react'; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore import DraftOffsetKey from 'draft-js/lib/DraftOffsetKey'; import { EditorState } from 'draft-js'; import { HeadlineOneButton, HeadlineTwoButton, BlockquoteButton, CodeBlockButton, UnorderedListButton, OrderedListButton, } from '@draft-js-plugins/buttons'; import BlockTypeSelect, { BlockTypeSelectChildProps, CreateBlockTypeSelectPopperOptionsFn, } from '../BlockTypeSelect/BlockTypeSelect'; import { SideToolbarPluginTheme } from '../../theme'; import { PopperOptions, SideToolbarPluginStore, SideToolbarPosition, } from '../..'; import Popover from './Popover'; import { SideToolbarButtonProps } from '../BlockTypeSelect/SideToolbarButton'; export type SideToolbarChildrenProps = BlockTypeSelectChildProps; interface ToolbarProps { children?: FC; store: SideToolbarPluginStore; position: SideToolbarPosition; theme: SideToolbarPluginTheme; popperOptions?: PopperOptions; createBlockTypeSelectPopperOptions?: CreateBlockTypeSelectPopperOptionsFn; sideToolbarButtonComponent: ComponentType; } function DefaultChildren( externalProps: SideToolbarChildrenProps ): ReactElement { // may be use React.Fragment instead of div to improve perfomance after React 16 return (
); } export default function Toolbar({ theme, position, popperOptions, store, createBlockTypeSelectPopperOptions, children = DefaultChildren, sideToolbarButtonComponent: SideToolbarButton, }: ToolbarProps): ReactElement | null { const [show, setShow] = useState(false); const [referenceElement, setReferenceElement] = useState( null ); const [buttonReferenceElement, setButtonReferenceElement] = useState(null); const onEditorStateChange = useCallback((editorState?: EditorState) => { const selection = editorState!.getSelection(); if (!selection.getHasFocus()) { setReferenceElement(null); setShow(false); return; } const currentContent = editorState!.getCurrentContent(); const currentBlock = currentContent.getBlockForKey(selection.getStartKey()); // TODO verify that always a key-0-0 exists const offsetKey = DraftOffsetKey.encode(currentBlock.getKey(), 0, 0); // Note: need to wait on tick to make sure the DOM node has been create by Draft.js setTimeout(() => { const node = document.querySelectorAll( `[data-offset-key="${offsetKey}"]` )[0]; setReferenceElement(node); }, 0); }, []); useEffect(() => { store.subscribeToItem('editorState', onEditorStateChange); return () => { store.unsubscribeFromItem('editorState', onEditorStateChange); }; }, [store]); if (referenceElement === null) { //do not show popover if reference element is not there return null; } return ( <>
setShow(true)} onMouseLeave={() => setShow(false)} >
); }