Skip to content

Commit ce737e3

Browse files
byseif21Miodec
andauthored
fix(caret): misalignment issue when switching between carets (@byseif21) (monkeytypegame#6642)
### Description fixes a caret misalignment issue that occurred when switching between caret styles (e.g., from block/outline/underline to line caret). #### Bug: When switching caret styles, the **line caret** could retain the width from the previous style (e.g., block), causing it to appear **visually incorrect** until the next input. #### Root Cause: * The caret's inline `width` was **not reset** when changing styles, so the new style inherited the old dimensions. * `updatePosition()` was called **before** the style was fully applied, leading to **incorrect positioning**. --- ### Fix * Added a `subscribe` listener in `caret.ts` for the `"caretStyle"` event. * When the caret style changes: * The caret's inline width is **reset**: ```ts caret.style.width = ""; ``` * Its position is immediately **recalculated** with: ```ts updatePosition(true); ``` --------- Co-authored-by: Miodec <[email protected]>
1 parent de447c2 commit ce737e3

File tree

1 file changed

+38
-16
lines changed

1 file changed

+38
-16
lines changed

frontend/src/ts/test/caret.ts

Lines changed: 38 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { prefersReducedMotion } from "../utils/misc";
88
import { convertRemToPixels } from "../utils/numbers";
99
import { splitIntoCharacters } from "../utils/strings";
1010
import { safeNumber } from "@monkeytype/util/numbers";
11+
import { subscribe } from "../observables/config-event";
1112

1213
export let caretAnimating = true;
1314
const caret = document.querySelector("#caret") as HTMLElement;
@@ -132,6 +133,27 @@ function getTargetPositionLeft(
132133
return result;
133134
}
134135

136+
function getLetterWidth(
137+
currentLetter: HTMLElement | undefined,
138+
activeWordEl: HTMLElement,
139+
wordLength: number,
140+
inputLength: number,
141+
currentWordNodeList: NodeListOf<HTMLElement>
142+
): number {
143+
let letterWidth = currentLetter?.offsetWidth;
144+
if (letterWidth === undefined || wordLength === 0) {
145+
// at word beginning in zen mode current letter is defined "_" but wordLen is 0
146+
letterWidth = getSpaceWidth(activeWordEl);
147+
} else if (letterWidth === 0) {
148+
// current letter is a zero-width character e.g, diacritics)
149+
for (let i = inputLength; i >= 0; i--) {
150+
letterWidth = (currentWordNodeList[i] as HTMLElement)?.offsetWidth;
151+
if (letterWidth) break;
152+
}
153+
}
154+
return letterWidth ?? 0;
155+
}
156+
135157
export async function updatePosition(noAnim = false): Promise<void> {
136158
const caretComputedStyle = window.getComputedStyle(caret);
137159
const caretWidth = parseInt(caretComputedStyle.width) || 0;
@@ -176,18 +198,13 @@ export async function updatePosition(noAnim = false): Promise<void> {
176198
newTop = activeWordEl.offsetTop + letterPosTop - caretHeight / 2;
177199
}
178200

179-
let letterWidth = currentLetter?.offsetWidth;
180-
if (letterWidth === undefined || wordLen === 0) {
181-
// at word beginning in zen mode current letter is defined "_" but wordLen is 0
182-
letterWidth = getSpaceWidth(activeWordEl);
183-
} else if (letterWidth === 0) {
184-
// current letter is a zero-width character e.g, diacritics)
185-
for (let i = inputLen; i >= 0; i--) {
186-
letterWidth = (currentWordNodeList[i] as HTMLElement)?.offsetWidth;
187-
if (letterWidth) break;
188-
}
189-
}
190-
const newWidth = fullWidthCaret ? (letterWidth ?? 0) + "px" : "";
201+
const letterWidth = getLetterWidth(
202+
currentLetter,
203+
activeWordEl,
204+
wordLen,
205+
inputLen,
206+
currentWordNodeList
207+
);
191208

192209
const letterPosLeft = getTargetPositionLeft(
193210
fullWidthCaret,
@@ -209,10 +226,8 @@ export async function updatePosition(noAnim = false): Promise<void> {
209226
left: newLeft,
210227
};
211228

212-
if (newWidth !== "") {
213-
animation.width = newWidth;
214-
} else {
215-
jqcaret.css("width", "");
229+
if (fullWidthCaret) {
230+
animation.width = `${letterWidth}px`;
216231
}
217232

218233
const smoothCaretSpeed =
@@ -250,6 +265,13 @@ export async function updatePosition(noAnim = false): Promise<void> {
250265
}
251266
}
252267

268+
subscribe((eventKey) => {
269+
if (eventKey === "caretStyle") {
270+
caret.style.width = "";
271+
void updatePosition(true);
272+
}
273+
});
274+
253275
export function show(noAnim = false): void {
254276
caret.classList.remove("hidden");
255277
void updatePosition(noAnim);

0 commit comments

Comments
 (0)