import React, { useMemo, useRef, useEffect } from 'react' import { Slate, Editable, withReact, useSlate, useFocused } from 'slate-react' import { Editor, Transforms, Text, createEditor, Descendant, Range, } from 'slate' import { css } from '@emotion/css' import { withHistory } from 'slate-history' import { Button, Icon, Menu, Portal } from '../components' const HoveringMenuExample = () => { const editor = useMemo(() => withHistory(withReact(createEditor())), []) return ( } placeholder="Enter some text..." onDOMBeforeInput={(event: InputEvent) => { switch (event.inputType) { case 'formatBold': event.preventDefault() return toggleFormat(editor, 'bold') case 'formatItalic': event.preventDefault() return toggleFormat(editor, 'italic') case 'formatUnderline': event.preventDefault() return toggleFormat(editor, 'underlined') } }} /> ) } const toggleFormat = (editor, format) => { const isActive = isFormatActive(editor, format) Transforms.setNodes( editor, { [format]: isActive ? null : true }, { match: Text.isText, split: true } ) } const isFormatActive = (editor, format) => { const [match] = Editor.nodes(editor, { match: n => n[format] === true, mode: 'all', }) return !!match } const Leaf = ({ attributes, children, leaf }) => { if (leaf.bold) { children = {children} } if (leaf.italic) { children = {children} } if (leaf.underlined) { children = {children} } return {children} } const HoveringToolbar = () => { const ref = useRef() const editor = useSlate() const inFocus = useFocused() useEffect(() => { const el = ref.current const { selection } = editor if (!el) { return } if ( !selection || !inFocus || Range.isCollapsed(selection) || Editor.string(editor, selection) === '' ) { el.removeAttribute('style') return } const domSelection = window.getSelection() const domRange = domSelection.getRangeAt(0) const rect = domRange.getBoundingClientRect() el.style.opacity = '1' el.style.top = `${rect.top + window.pageYOffset - el.offsetHeight}px` el.style.left = `${rect.left + window.pageXOffset - el.offsetWidth / 2 + rect.width / 2}px` }) return ( { // prevent toolbar from taking focus away from editor e.preventDefault() }} > ) } const FormatButton = ({ format, icon }) => { const editor = useSlate() return ( ) } const initialValue: Descendant[] = [ { type: 'paragraph', children: [ { text: 'This example shows how you can make a hovering menu appear above your content, which you can use to make text ', }, { text: 'bold', bold: true }, { text: ', ' }, { text: 'italic', italic: true }, { text: ', or anything else you might want to do!' }, ], }, { type: 'paragraph', children: [ { text: 'Try it out yourself! Just ' }, { text: 'select any piece of text and the menu will appear', bold: true }, { text: '.' }, ], }, ] export default HoveringMenuExample