diff --git a/src/lib/components/Keyboard.ts b/src/lib/components/Keyboard.ts index 19513260..46f06e7b 100644 --- a/src/lib/components/Keyboard.ts +++ b/src/lib/components/Keyboard.ts @@ -1190,10 +1190,15 @@ class SimpleKeyboard { * Tracks current cursor position * As keys are pressed, text will be added/removed at that position within the input. */ - instance.setCaretPosition( - event.target.selectionStart, - event.target.selectionEnd - ); + let selectionStart = event.target.selectionStart; + let selectionEnd = event.target.selectionEnd; + + if(instance.options.rtl){ + selectionStart = instance.utilities.getRtlOffset(selectionStart, instance.getInput()); + selectionEnd = instance.utilities.getRtlOffset(selectionEnd, instance.getInput()); + } + + instance.setCaretPosition(selectionStart, selectionEnd); /** * Tracking current input in order to handle caret positioning edge cases diff --git a/src/lib/components/tests/Keyboard.test.js b/src/lib/components/tests/Keyboard.test.js index 505ca9f9..d1a630e1 100644 --- a/src/lib/components/tests/Keyboard.test.js +++ b/src/lib/components/tests/Keyboard.test.js @@ -1351,4 +1351,54 @@ it('Keyboard will handle selected input with unchanged updatedInput edge case', expect(keyboard.getInput()).toBe("33"); expect(keyboard.getCaretPosition()).toBe(2); expect(keyboard.getCaretPositionEnd()).toBe(2); +}); + +it('Ensure caret position is offset when rtl option is enabled', () => { + const keyboard = new Keyboard({ + useMouseEvents: true, + rtl: true, + layout: { + default: ["{bksp} ש ל ו ם"] + } + }); + + const caretEventHandler = jest.spyOn(keyboard, 'caretEventHandler'); + + keyboard.getButtonElement("ש").onclick(); + keyboard.getButtonElement("ו").onclick(); + keyboard.getButtonElement("ם").onclick(); + + expect(keyboard.getInput()).toBe("‫שום‬"); + + const input = document.createElement("input"); + input.value = keyboard.getInput(); + input.type = "text"; + input.selectionStart = 2; + input.selectionEnd = 2; + + keyboard.caretEventHandler({ + type: "selectionchange", + target: input + }); + + expect(caretEventHandler).toHaveBeenCalled(); + expect(keyboard.getCaretPosition()).toBe(1); + + keyboard.getButtonElement("ל").onclick(); + + expect(keyboard.getInput()).toBe('‫שלום‬'); + + input.value = keyboard.getInput(); + input.type = "text"; + input.selectionStart = 4; + input.selectionEnd = 4; + + keyboard.caretEventHandler({ + type: "selectionchange", + target: input + }); + + keyboard.getButtonElement("{bksp}").onclick(); + + expect(keyboard.getInput()).toBe('‫שלם‬'); }); \ No newline at end of file diff --git a/src/lib/services/Utilities.ts b/src/lib/services/Utilities.ts index 3569514e..a2473853 100644 --- a/src/lib/services/Utilities.ts +++ b/src/lib/services/Utilities.ts @@ -539,6 +539,20 @@ class Utilities { return str.replace(/[-\/\\^$*+?.()|[\]{}]/g, "\\$&"); } + /** + * Calculate caret position offset when using rtl option + */ + getRtlOffset(index: number, input: string) { + let newIndex = index; + const startMarkerIndex = input.indexOf("\u202B"); + const endMarkerIndex = input.indexOf("\u202C"); + + if(startMarkerIndex < index && startMarkerIndex != -1){ newIndex--; } + if(endMarkerIndex < index && startMarkerIndex != -1){ newIndex--; } + + return newIndex < 0 ? 0 : newIndex; + } + /** * Reusable empty function */