-
Notifications
You must be signed in to change notification settings - Fork 28
Description
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>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);