From 0f32b0e556e4aff09f10d2a78ae1d32b8dec2456 Mon Sep 17 00:00:00 2001 From: Harnoor Singh Date: Tue, 20 Oct 2026 11:29:29 -0700 Subject: [PATCH 1/2] fix(ios): put the key-term field's caret before the placeholder On an empty field the blinking caret was drawn after the placeholder ("New key term|"), where nothing will be typed. A system text field draws it at the start ("|New key term") and only follows the text once there is some. TermField now does the same: caret first on an empty field, after the draft once one exists, with its gap on the side facing the text. Co-Authored-By: Claude Opus 5.5 --- App/BlurtiOS/BlurtKeyboard/Sources/TermField.swift | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/App/BlurtiOS/BlurtKeyboard/Sources/TermField.swift b/App/BlurtiOS/BlurtKeyboard/Sources/TermField.swift index e386c5eb..48f0c093 100644 --- a/App/BlurtiOS/BlurtKeyboard/Sources/TermField.swift +++ b/App/BlurtiOS/BlurtKeyboard/Sources/TermField.swift @@ -16,12 +16,16 @@ struct TermField: View { model.cancelAddingTerm() } HStack(spacing: 0) { + // The caret sits where the next character lands: after what has been + // typed, or — on an empty field — at the start, ahead of the + // placeholder, as a system text field draws it. if let draft = model.termDraft, !draft.isEmpty { Text(draft).foregroundStyle(palette.keyText) + Caret(gap: .leading) } else { + Caret(gap: .trailing) Text("New key term").foregroundStyle(palette.keyText.opacity(DesignTokens.Metrics.opacityPlaceholder)) } - Caret() Spacer(minLength: 0) } .font(.system(size: DesignTokens.Typography.sizeTerm, weight: DesignTokens.Typography.weightTerm)) @@ -45,6 +49,8 @@ struct TermField: View { /// A blinking caret, as a text field's; held on while motion is held. private struct Caret: View { + /// The side the caret keeps its gap on — toward the text beside it. + var gap: Edge.Set @Environment(\.keyboardPalette) private var palette @Environment(\.keyboardMotionHeld) private var motionHeld @@ -55,7 +61,7 @@ private struct Caret: View { .fill(palette.signal) .frame(width: DesignTokens.Metrics.caretWidth, height: DesignTokens.Metrics.caretHeight) .opacity(on ? 1 : 0) - .padding(.leading, DesignTokens.Metrics.caretLead) + .padding(gap, DesignTokens.Metrics.caretLead) } .accessibilityHidden(true) } From 0875c3c8af58b7e2ee889881415d5bd482907e00 Mon Sep 17 00:00:00 2001 From: Harnoor Singh Date: Tue, 20 Oct 2026 12:30:04 -0700 Subject: [PATCH 2/2] Drop the comments from the caret fix Co-Authored-By: Claude Opus 5.5 --- App/BlurtiOS/BlurtKeyboard/Sources/TermField.swift | 4 ---- 1 file changed, 4 deletions(-) diff --git a/App/BlurtiOS/BlurtKeyboard/Sources/TermField.swift b/App/BlurtiOS/BlurtKeyboard/Sources/TermField.swift index 48f0c093..14c8e8e6 100644 --- a/App/BlurtiOS/BlurtKeyboard/Sources/TermField.swift +++ b/App/BlurtiOS/BlurtKeyboard/Sources/TermField.swift @@ -16,9 +16,6 @@ struct TermField: View { model.cancelAddingTerm() } HStack(spacing: 0) { - // The caret sits where the next character lands: after what has been - // typed, or — on an empty field — at the start, ahead of the - // placeholder, as a system text field draws it. if let draft = model.termDraft, !draft.isEmpty { Text(draft).foregroundStyle(palette.keyText) Caret(gap: .leading) @@ -49,7 +46,6 @@ struct TermField: View { /// A blinking caret, as a text field's; held on while motion is held. private struct Caret: View { - /// The side the caret keeps its gap on — toward the text beside it. var gap: Edge.Set @Environment(\.keyboardPalette) private var palette @Environment(\.keyboardMotionHeld) private var motionHeld