diff --git a/packages/web/src/javascripts/Components/SuperEditor/BlocksEditor.tsx b/packages/web/src/javascripts/Components/SuperEditor/BlocksEditor.tsx index 81b39e7d6..25b852923 100644 --- a/packages/web/src/javascripts/Components/SuperEditor/BlocksEditor.tsx +++ b/packages/web/src/javascripts/Components/SuperEditor/BlocksEditor.tsx @@ -28,6 +28,7 @@ import TableActionMenuPlugin from './Plugins/TableCellActionMenuPlugin' import ToolbarPlugin from './Plugins/ToolbarPlugin/ToolbarPlugin' import { useMediaQuery, MutuallyExclusiveMediaQueryBreakpoints } from '@/Hooks/useMediaQuery' import { CheckListPlugin } from './Plugins/List/CheckListPlugin' +import { LinePlaceholderPlugin } from './Plugins/LinePlaceholderPlugin' type BlocksEditorProps = { onChange?: (value: string, preview: string) => void @@ -113,6 +114,7 @@ export const BlocksEditor: FunctionComponent = ({ + {!readonly && floatingAnchorElem && ( <> diff --git a/packages/web/src/javascripts/Components/SuperEditor/Plugins/LinePlaceholderPlugin.tsx b/packages/web/src/javascripts/Components/SuperEditor/Plugins/LinePlaceholderPlugin.tsx new file mode 100644 index 000000000..2b6c0976f --- /dev/null +++ b/packages/web/src/javascripts/Components/SuperEditor/Plugins/LinePlaceholderPlugin.tsx @@ -0,0 +1,90 @@ +import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext' +import { + $getSelection, + $isRangeSelection, + $isParagraphNode, + $isTextNode, + SELECTION_CHANGE_COMMAND, + COMMAND_PRIORITY_LOW, +} from 'lexical' +import { useCallback, useEffect, useRef } from 'react' +import { getSelectedNode } from '../Lexical/Utils/getSelectedNode' +import { mergeRegister } from '@lexical/utils' + +export const LinePlaceholderPlugin = () => { + const [editor] = useLexicalComposerContext() + + const placeholderElementRef = useRef(null) + + const cursorUpdate = useCallback((): boolean => { + const selection = $getSelection() + if (selection && $isRangeSelection(selection)) { + if (!placeholderElementRef.current) { + return false + } + const node = getSelectedNode(selection) + if (!node) { + return false + } + const isParagraph = $isParagraphNode(node) || $isTextNode(node) + const text = node.getTextContent() + if (!isParagraph) { + return false + } + const rootElement = editor.getRootElement() + const nodeElement = editor.getElementByKey(node.getKey()) + const placeholder = placeholderElementRef.current + if (!nodeElement || !placeholder.parentElement || !rootElement) { + return false + } + const rect = nodeElement.getBoundingClientRect() + const parentRect = placeholder.parentElement.getBoundingClientRect() + const rootRect = rootElement.getBoundingClientRect() + if (!text && editor.isEditable()) { + placeholder.style.top = `${rect.y}px` + placeholder.style.left = `${rect.x - parentRect.x + rootRect.x}px` + placeholder.style.opacity = '1' + } else { + placeholder.style.opacity = '0' + } + } + + return false + }, [editor]) + + useEffect(() => { + return mergeRegister( + editor.registerCommand(SELECTION_CHANGE_COMMAND, cursorUpdate, COMMAND_PRIORITY_LOW), + editor.registerEditableListener(cursorUpdate), + ) + }, [cursorUpdate, editor]) + + useEffect(() => { + const scrollerElem = editor.getRootElement() + + const update = () => { + editor.getEditorState().read(() => { + cursorUpdate() + }) + } + + window.addEventListener('resize', update) + if (scrollerElem) { + scrollerElem.addEventListener('scroll', update) + } + + return () => { + window.removeEventListener('resize', update) + if (scrollerElem) { + scrollerElem.removeEventListener('scroll', update) + } + } + }, [cursorUpdate, editor]) + + return ( +
+ Type / for + commands... +
+ ) +} diff --git a/packages/web/src/javascripts/Components/SuperEditor/SuperEditor.tsx b/packages/web/src/javascripts/Components/SuperEditor/SuperEditor.tsx index 498a716de..78809b7d1 100644 --- a/packages/web/src/javascripts/Components/SuperEditor/SuperEditor.tsx +++ b/packages/web/src/javascripts/Components/SuperEditor/SuperEditor.tsx @@ -210,7 +210,14 @@ export const SuperEditor: FunctionComponent = ({ }, []) return ( -
+
{featureStatus !== FeatureStatus.Entitled && ( )}