Skip to content

Add RTL support#99

Merged
alecgibson merged 3 commits intoreedsy:mainfrom
fyvfyv:rtl-cursor-positioning
Mar 4, 2026
Merged

Add RTL support#99
alecgibson merged 3 commits intoreedsy:mainfrom
fyvfyv:rtl-cursor-positioning

Conversation

@fyvfyv
Copy link
Contributor

@fyvfyv fyvfyv commented Feb 28, 2026

  • Detect text direction from the DOM and adjust cursor caret position for RTL text (Hebrew, Arabic, etc.)
  • Quill's getBounds() returns width: 0 for cursor positions, so RTL caret position is computed directly from character bounding rects via document.createRange()
  • Direction detection uses fast dir attribute lookup, falling back to getComputedStyle for CSS-only direction
  • No breaking changes — fully backward compatible

Fix #86

- Detect text direction from the DOM and adjust cursor caret position for RTL text (Hebrew, Arabic, etc.)
- Quill's `getBounds()` returns `width: 0` for cursor positions, so RTL caret position is computed directly from character bounding rects via `document.createRange()`
- Direction detection uses fast `dir` attribute lookup, falling back to `getComputedStyle` for CSS-only direction
- No breaking changes — fully backward compatible
@fyvfyv fyvfyv force-pushed the rtl-cursor-positioning branch from 3d8db9f to 23f9a44 Compare February 28, 2026 21:55
@fyvfyv
Copy link
Contributor Author

fyvfyv commented Feb 28, 2026

@alecgibson Could you please review this PR when you get a chance?

Also, the ESLint config used in this repo relies on a private @reedsy/eslint-plugin, so external contributors can't run linting locally and have to rely solely on CI, which is quite inconvenient.

Thanks!

Comment on lines +211 to +212
const dirEl = element.closest('[dir]');
if (dirEl) return (dirEl as HTMLElement).dir === 'rtl';
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be covered by getComputedStyle()? Is it here for performance? If so, I think I'd rather we start with one "canonical" way of figuring out the direction with getComputedStyle() and then see if this becomes an issue. Also, direction can be set through CSS, so you can in theory have this sort of thing:

<div dir="rtl">
  <div style="direction: ltr;"></div>
</div>

And this current code would incorrectly say that we're in an RTL environment when we're actually not.

Copy link
Contributor Author

@fyvfyv fyvfyv Mar 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch You're right - the closest('[dir]') shortcut is both redundant and buggy. Simplified _isRtl to only use getComputedStyle(element).direction.

Comment on lines +187 to +196
const range = document.createRange();
if (offset < node.data.length) {
range.setStart(node, offset);
range.setEnd(node, offset + 1);
} else {
range.setStart(node, offset - 1);
range.setEnd(node, offset);
}

const charRect = range.getBoundingClientRect();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Took me a minute to figure out what we were doing here (sorry I haven't thought hard about RTL before). Might be helpful to move this to a function named something (long and) obvious like getWidthOfCharacterToRightOfCursor()

Copy link
Contributor Author

@fyvfyv fyvfyv Mar 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, extracted it into _getCharacterRectAtCursor(node, offset). It returns a DOMRect for the character adjacent to the cursor offset. Open to a different name if you have a preference.

@fyvfyv fyvfyv requested a review from alecgibson March 4, 2026 12:16
Copy link
Collaborator

@alecgibson alecgibson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

شكراً

@alecgibson alecgibson merged commit 618969a into reedsy:main Mar 4, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Cursor position is incorrect when direction is RTL

2 participants