Skip to content

Commit 43976e7

Browse files
committed
Fix issue where multiple instances would not sync caret position
1 parent 58f8c10 commit 43976e7

2 files changed

Lines changed: 69 additions & 4 deletions

File tree

src/lib/components/Keyboard.ts

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1233,10 +1233,20 @@ class SimpleKeyboard {
12331233
* If syncInstanceInputs option is enabled, make isKeyboard match any instance
12341234
* not just the current one
12351235
*/
1236-
if (this.options.syncInstanceInputs && Array.isArray(event.path)) {
1237-
isKeyboard = event.path.some((item: HTMLElement) =>
1238-
item?.hasAttribute?.("data-skInstance")
1239-
);
1236+
if (this.options.syncInstanceInputs) {
1237+
// `event.path` is a legacy Chrome property that no longer exists; without
1238+
// composedPath() every other instance saw a sibling's key press as a click
1239+
// outside and dropped its caret, so the next instance typed at the end.
1240+
const eventPath =
1241+
typeof event.composedPath === "function"
1242+
? event.composedPath()
1243+
: event.path;
1244+
1245+
if (Array.isArray(eventPath)) {
1246+
isKeyboard = eventPath.some((item: HTMLElement) =>
1247+
item?.hasAttribute?.("data-skInstance")
1248+
);
1249+
}
12401250
}
12411251

12421252
if (

src/lib/components/tests/Keyboard.test.js

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,61 @@ it('Keyboard syncInstanceInputs will work', () => {
203203
expect(keyboard2.getInput()).toBe("123456");
204204
});
205205

206+
it('Keyboard syncInstanceInputs keeps the caret when another instance is pressed', () => {
207+
clearDOM();
208+
209+
document.body.innerHTML = `
210+
<input class="input" />
211+
<div class="keyboard1"></div>
212+
<div class="keyboard2"></div>
213+
`;
214+
215+
const sharedOptions = { syncInstanceInputs: true };
216+
const keyboard1 = new Keyboard(".keyboard1", sharedOptions);
217+
const keyboard2 = new Keyboard(".keyboard2", sharedOptions);
218+
219+
const input = document.querySelector(".input");
220+
input.value = "abcdef";
221+
input.selectionStart = 3;
222+
input.selectionEnd = 3;
223+
224+
keyboard1.caretEventHandler({ target: input, type: "select" });
225+
226+
expect(keyboard2.getCaretPosition()).toBe(3);
227+
228+
// A press on keyboard1 reaches the document as a click outside keyboard2. Only the
229+
// event path tells keyboard2 this came from a sibling instance rather than elsewhere.
230+
const pressed = keyboard1.keyboardDOM.querySelector(".hg-button");
231+
keyboard2.caretEventHandler({
232+
target: pressed,
233+
type: "mouseup",
234+
composedPath: () => [pressed, keyboard1.keyboardDOM, document.body]
235+
});
236+
237+
expect(keyboard2.getCaretPosition()).toBe(3);
238+
});
239+
240+
it('Keyboard caretEventHandler drops the caret for a click outside any instance', () => {
241+
clearDOM();
242+
243+
document.body.innerHTML = `
244+
<div class="outside"></div>
245+
<div class="keyboard1"></div>
246+
`;
247+
248+
const keyboard = new Keyboard(".keyboard1", { syncInstanceInputs: true });
249+
keyboard.setCaretPosition(2);
250+
251+
const outside = document.querySelector(".outside");
252+
keyboard.caretEventHandler({
253+
target: outside,
254+
type: "mouseup",
255+
composedPath: () => [outside, document.body]
256+
});
257+
258+
expect(keyboard.getCaretPosition()).toBe(null);
259+
});
260+
206261
it('Keyboard onChange will work', () => {
207262
let output = false;
208263

0 commit comments

Comments
 (0)