For my draftjs
project, I want to enable the user to insert a link. To do that, I had created a popup after pressing the shortcut cmk + k
.
For better user experience, I am currently trying to smart align the popup.
See the above picture, I am able to position the popup below the current focus line. The bounding rect object of the Editor-container and the current selection's bounding rect would contain enough information for me to finish the calculation.
However, in other cases, when there's an empty line only:
(The cursor's position before the popup is at the end of the editor)
The
window.getSelection().getRangeAt(0).getBoundingClientRect()
would return the DOMRect object with every value is 0. Is there any way around in dom, or in draftjs
that I could attain enough information to smart align the popup? So the popup could pop up around the current cursor position.
To solve this issue, I used the block index of the cursor multiplied by the line height + some offsets to achieve correct placement from the top when an empty line is selected.
This is code from my "calculate position of popup" function. I've excluded parts for getting the top/left positions when a line with text is selected and just included when I need to account for lines with no text when getBoundingClientRect() returns null.
const singleLineHeightOffset = 28;
const topBlankLineOffset = 15;
let position = getVisibleSelectionRect(window);
// If there is a visible selection area
if (position) {
// Get ref of editor via prop and location of div if exists
let editorRef = forwardedRef;
element = ReactDOM.findDOMNode(editorRef.current) as HTMLElement;
if (element) {
// Code here to calculate when a line with text is selected
} else {
// Else if no text selected on line
// Get current block position of cursor
const currentBlockKey = editorState.getSelection().getStartKey();
const currentBlockIndex = editorState
.getCurrentContent()
.getBlockMap()
.keySeq()
.findIndex((k) => k === currentBlockKey);
let emptyLineTopHeight =
singleLineHeightOffset * (currentBlockIndex + 1) - 5;
// If first line of editor, add offset for toolbar/padding
if (currentBlockIndex === 0) emptyLineTopHeight += topBlankLineOffset;
setTopPosition(emptyLineTopHeight);
}
This will detect what line the empty cursor is on, then creates the top offset by multiplying with your line height. You may need to play around with the offsets and edge cases such as initial line like I did.