import React, { useState, useMemo, useRef, useEffect } from 'react' import { Slate, Editable, ReactEditor, withReact, useSlate } from 'slate-react' import { Editor, Transforms, Text, createEditor, Node, Element, Descendant, } from 'slate' import { css } from 'emotion' import { withHistory } from 'slate-history' import { Button, Icon, Menu, Portal } from '../components' import { Range } from 'slate' const HoveringMenuExample = () => { const [value, setValue] = useState(initialValue) const editor = useMemo(() => withHistory(withReact(createEditor())), []) return ( setValue(value)}> } placeholder="Enter some text..." onDOMBeforeInput={(event: InputEvent) => { event.preventDefault() switch (event.inputType) { case 'formatBold': return toggleFormat(editor, 'bold') case 'formatItalic': return toggleFormat(editor, 'italic') case 'formatUnderline': return toggleFormat(editor, 'underline') } }} /> ) } 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() useEffect(() => { const el = ref.current const { selection } = editor if (!el) { return } if ( !selection || !ReactEditor.isFocused(editor) || 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 ( ) } const FormatButton = ({ format, icon }) => { const editor = useSlate() return ( ) } const initialValue: Element[] = [ { 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