Finding width of selection and select-all

I’m building a function that should center a tooltip around selection.

const { from, to } = editor.state.selection
const start = editor.coordsAtPos(from)
const end = editor.coordsAtPos(to)
const width = end.left > start.left ? end.left - start.left : start.left - end.left

This works well when selection is manually selected with a cursor. But when using a keyboard Cmd+A to “select all”, the left position of from and to is reported as the same.

There is the same issue can be found in the prosemirror tooltip example - the tooltip is not centered when “select all” hotkey is used.

Is there any other way to find selection width in this situation ?

That code is just getting the X offset of the start and end positions and getting the delta of those. That won’t account for how wide the elements are within that range. If the from/to are both vertically aligned (e.g. from is the start of one line and to is the start of another line) then the resulting width is going to be zero; it has nothing to do with the manner in which you created that selection. You’d have to union the rects of all the elements within the range. You’re probably better off using the available browse apis - e.g. get the selection and get the range(s) and using the getBoundingClientRect of the range(s).

What do you mean getBoundingClientRect on the ranges ? The range is not a dom element. You can find the selection’s dom element(s), but that’s not so trivial considering that the selection might touch part of the node and there can be many nodes in the selection. For example, on this dom <p><a href="link" title=""><em>this<strong> is a</strong></em><strong> selection</strong></a></p>, consider that the text s is a sel is selected, how would you find the width within those nodes ?

As I said, the delta of start and end positions works quite well, except for the “select all” case mentioned.

I linked to the getBoundingClientRect I was referring to - that of the browser’s Range class - that you might get from the getRangeAt of the browser’s Selection class. I was saying that you could instead get the selection from the browser and let it provide the bounding rect. If there are multiple ranges then you could manually union those or however you want to treat that.

As I said this is not specific to select all. Here’s a mouse made selection from the start of a line to the start of the next line and notice how the tooltip is left aligned for the same reason:

Or here’s another case with keyboard driven selection:

All that matters to cause the issue is what is the x/horizontal offset of the selection start and the x/horizontal offset of the selection end since that is all that is considered in that snippet you have.