fleather icon indicating copy to clipboard operation
fleather copied to clipboard

How to get caret offset?

Open nialljawad96 opened this issue 1 year ago • 6 comments

Is there a way to calculate the offset created by a bullet point (or any other type of block for that matter), relative to a normal line of text?

nialljawad96 avatar Jan 09 '24 18:01 nialljawad96

Do you mean the empty space added to the leading of the text in compare to normal paragraphs? Why do you need such a thing?

Amir-P avatar Jan 10 '24 05:01 Amir-P

@Amir-P hi Amir, thanks for your reply. Yes, i indeed mean that empty space. I'm building a hovering bar (with Bold, Italic etc), like Notion, which needs the TextPosition:

final TextPosition position = TextPosition(offset: controller.selection.baseOffset );

and textSpan painter:

final TextPainter textPainter = TextPainter(
      text: textSpan,
      textDirection: TextDirection.ltr,
    );

to get the caretOffset, so that I can display the bar in the correct place. The problem is that when I use a bullet point (or another block for that matter), it indents it, meaning the textPainter.layout ends up being incorrect by a slight amount. This error builds up the further down the text you try and get the caretOffset, as of course the text is offsetted by more and more bullet points.

nialljawad96 avatar Jan 10 '24 10:01 nialljawad96

Hey, in order to get the caret offset without dealing with rendering details you can use the already exposed APIs of RenderEditor and RenderEditableBox. Here is a working code (editorKey is a GlobalKey<EditorState> assigned to FleatherEditor or FleatherField's editorKey parameter):

  Offset getCaretGlobalOffset() {
    final editor = editorKey.currentState!.renderEditor;
    final globalTextPosition = editor.selection.base;
    final childAtPosition = editor.childAtPosition(globalTextPosition);
    final localTextPosition =
        childAtPosition.globalToLocalPosition(globalTextPosition);
    final localOffsetForCaret =
        childAtPosition.getOffsetForCaret(localTextPosition);
    return childAtPosition.localToGlobal(localOffsetForCaret);
  }

Amir-P avatar Jan 10 '24 11:01 Amir-P

@Amir-P this works perfectly. Genius! Much appreciated, thanks.

nialljawad96 avatar Jan 10 '24 11:01 nialljawad96

You're welcome! I'm gonna rename the issue so that other users can find the answer easier.

Amir-P avatar Jan 10 '24 11:01 Amir-P

For some reason, the offset given by the function above (getCaretGlobalOffset()) is different in these two scenarios:

  1. You're typing to a certain position, stop and then calculate the offset.
  2. You type to the same position, you stop, click on another part of the text, then click again on the last part of the text you were typing at, and calculate the offset.

The two offsets are the different, even though they should be the same

nialljawad96 avatar Feb 15 '24 19:02 nialljawad96