Skip to content

Proposal: setCaretInlineOffset API for adjusting caret visual representation #347

@mozesstumpf

Description

@mozesstumpf

Problem

Rich text editors face challenges with caret positioning when text is broken into multiple line boxes due to responsive layouts, because a single boundary point can be visually rendered in 2 different places.

For example, a boundary-point like {node: #text, offset: 5} in the following HTML:

<p style="word-break: break-all">loremipsum</p>

Image

When we use the browser's default event to navigate, it uses its "internal state" to know where the caret should be placed. However, if we want to implement the block-directional / inline-directional navigation manually, we have no control over the caret's visual placement.

Proposal

I'd like to propose to extend the Selection API by adding a new method that allows developers to set an inline offset for the caret’s visual appearance.

interface Selection {
  setCaretInlineOffset: (offset: number) => void;
}

How would it work?

It checks if the caret should be appeared, then
if the caret can be placed in 2 different places, then
if the diff between offsetA and offset is smaller than the diff between offsetB and offset, position the caret to the place A, otherwise position it to the place B.

Example

const textNode = document.createTextNode("loremipsum");

// We get the char's left and right pos
const getCharPos = (text, index) => {
	const range = new Range();

	range.setStart(text, index);
	range.setEnd(text, index + 1);

	const { left: charLeftPos, right: charRightPos } =
		range.getBoundingClientRect();

	return { charLeftPos, charRightPos };
};

// We select the char m (lore[m]ipsum)
const char_M_Pos = getCharPos(textNode, 4);

// We select the char i (lorem[i]psum)
const char_I_Pos = getCharPos(textNode, 5);

const sel = getSelection();

// Set the bp to lorem|ipsum
sel.setPosition(textNode, 5);

// If we want to adjust right after lorem
sel.setCaretInlineOffset(char_M_Pos.charRightPos);

// If we want to adjust right before ipsum
sel.setCaretInlineOffset(char_I_Pos.charLeftPos);

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions