Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions apps/mobile/.swiftlint.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
included:
- ios/T3Code
- modules/t3-composer-editor/ios
- modules/t3-terminal/ios
- modules/t3-review-diff/ios

Expand Down
22 changes: 21 additions & 1 deletion apps/mobile/global.css
Original file line number Diff line number Diff line change
Expand Up @@ -192,11 +192,31 @@
}
}

/* ─── Font family ───────────────────────────────────────────────────── */
/* ─── Typography ────────────────────────────────────────────────────── */
@theme {
--font-sans: "DMSans_400Regular";
--font-medium: "DMSans_500Medium";
--font-bold: "DMSans_700Bold";

/* Keep this scale aligned with src/lib/typography.ts for native style props. */
--text-3xs: 10px;
--text-3xs--line-height: 13px;
--text-2xs: 11px;
--text-2xs--line-height: 15px;
--text-xs: 12px;
--text-xs--line-height: 16px;
--text-sm: 13px;
--text-sm--line-height: 18px;
--text-base: 15px;
--text-base--line-height: 22px;
--text-lg: 17px;
--text-lg--line-height: 22px;
--text-xl: 20px;
--text-xl--line-height: 26px;
--text-2xl: 24px;
--text-2xl--line-height: 30px;
--text-3xl: 28px;
--text-3xl--line-height: 34px;
}

/* ─── Custom utilities ──────────────────────────────────────────────── */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -275,8 +275,8 @@ public final class T3ComposerEditorView: ExpoView, UITextViewDelegate {
fileTint: "#737373"
)
private var fontFamily = "DMSans_400Regular"
private var fontSize: CGFloat = 15
private var lineHeight: CGFloat = 22
private var fontSize: CGFloat = 14
private var lineHeight: CGFloat = 20
private var contentInsetVertical: CGFloat = 0
private var shouldAutoFocus = false
private var didAutoFocus = false
Expand Down Expand Up @@ -460,9 +460,19 @@ public final class T3ComposerEditorView: ExpoView, UITextViewDelegate {
guard !isApplyingControlledValue else {
return
}
restoreBaseTypingAttributes()
emitSelection()
}

public func textView(
_ textView: UITextView,
shouldChangeTextIn range: NSRange,
replacementText text: String
) -> Bool {
restoreBaseTypingAttributes()
return true
}

public func textViewDidBeginEditing(_ textView: UITextView) {
onComposerFocus()
}
Expand All @@ -484,6 +494,7 @@ public final class T3ComposerEditorView: ExpoView, UITextViewDelegate {
let targetSelection = requestedSelection ?? previousSelection
requestedSelection = nil
textView.selectedRange = displayRange(for: targetSelection)
restoreBaseTypingAttributes()
isApplyingControlledValue = false
updatePlaceholderVisibility()
emitContentSizeIfNeeded()
Expand Down Expand Up @@ -556,7 +567,12 @@ public final class T3ComposerEditorView: ExpoView, UITextViewDelegate {
size: image.size,
baselineOffset: baselineOffset
)
return NSAttributedString(attachment: attachment)
let attributedAttachment = NSMutableAttributedString(attachment: attachment)
attributedAttachment.addAttributes(
baseAttributes(),
range: NSRange(location: 0, length: attributedAttachment.length)
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Inline chips clip line height

Medium Severity

Applying baseAttributes() to inline attachments in makeAttachmentString forces a 20pt line height on token glyphs. This conflicts with renderChip still drawing 24pt tall chip images, causing file/skill chips to clip or misalign in the composer.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 124e471. Configure here.

return attributedAttachment
}

private func renderChip(
Expand Down Expand Up @@ -660,11 +676,18 @@ public final class T3ComposerEditorView: ExpoView, UITextViewDelegate {
let font = UIFont(name: fontFamily, size: fontSize)
?? UIFont.systemFont(ofSize: fontSize)
textView.font = font
textView.typingAttributes = baseAttributes()
restoreBaseTypingAttributes()
placeholderLabel.font = font
setNeedsLayout()
}

private func restoreBaseTypingAttributes() {
guard textView.markedTextRange == nil else {
return
}
textView.typingAttributes = baseAttributes()
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Selection sync skips typing restore

Medium Severity

applyRequestedSelection updates the caret from React selectionJson while isApplyingControlledValue is true, so textViewDidChangeSelection returns before restoreBaseTypingAttributes. Unlike applyControlledDocument, this path never restores typing attributes after UIKit clears them on programmatic selection moves.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 124e471. Configure here.

private func applyTheme() {
textView.textColor = UIColor(composerHex: theme.text) ?? .label
placeholderLabel.textColor = UIColor(composerHex: theme.placeholder) ?? .placeholderText
Expand Down
4 changes: 2 additions & 2 deletions apps/mobile/src/app/+not-found.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export default function NotFoundRoute() {
}}
style={[{ flex: 1 }, screenBgStyle]}
>
<Text className="text-[28px] font-t3-bold text-foreground" selectable>
<Text className="text-3xl font-t3-bold text-foreground" selectable>
Route not found
</Text>
<Link href="/" asChild>
Expand All @@ -35,7 +35,7 @@ export default function NotFoundRoute() {
primaryBgStyle,
]}
>
<Text className="text-[16px] font-t3-bold text-primary-foreground">Return home</Text>
<Text className="text-base font-t3-bold text-primary-foreground">Return home</Text>
</Pressable>
</Link>
</ScrollView>
Expand Down
2 changes: 1 addition & 1 deletion apps/mobile/src/app/connections/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ export default function ConnectionsRouteScreen() {
type="monochrome"
/>
</View>
<Text className="text-center text-[14px] leading-[20px] text-foreground-muted">
<Text className="text-center text-sm leading-[20px] text-foreground-muted">
No environments connected yet.{"\n"}Tap{" "}
<Text className="font-t3-bold text-foreground">+</Text> to add one.
</Text>
Expand Down
10 changes: 5 additions & 5 deletions apps/mobile/src/app/connections/new.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ export default function ConnectionsNewRouteScreen() {
className="items-center gap-3 rounded-[24px] bg-card px-5 py-8"
style={{ borderCurve: "continuous" }}
>
<Text className="text-center text-[14px] leading-[20px] text-foreground-muted">
<Text className="text-center text-sm leading-[20px] text-foreground-muted">
Camera permission is required to scan a QR code.
</Text>
<ConnectionSheetButton
Expand All @@ -189,7 +189,7 @@ export default function ConnectionsNewRouteScreen() {
<View collapsable={false} className="gap-4 rounded-[24px] bg-card p-4">
<View collapsable={false} className="gap-1.5">
<Text
className="text-[11px] font-t3-bold uppercase text-foreground-muted"
className="text-2xs font-t3-bold uppercase text-foreground-muted"
style={{ letterSpacing: 0.8 }}
>
Host
Expand All @@ -202,13 +202,13 @@ export default function ConnectionsNewRouteScreen() {
placeholderTextColor={placeholderColor}
value={hostInput}
onChangeText={handleHostChange}
className="rounded-[14px] border border-input-border bg-input px-4 py-3.5 text-[15px] text-foreground"
className="rounded-[14px] border border-input-border bg-input px-4 py-3.5 text-base text-foreground"
/>
</View>

<View collapsable={false} className="gap-1.5">
<Text
className="text-[11px] font-t3-bold uppercase text-foreground-muted"
className="text-2xs font-t3-bold uppercase text-foreground-muted"
style={{ letterSpacing: 0.8 }}
>
Pairing code
Expand All @@ -220,7 +220,7 @@ export default function ConnectionsNewRouteScreen() {
placeholderTextColor={placeholderColor}
value={codeInput}
onChangeText={handleCodeChange}
className="rounded-[14px] border border-input-border bg-input px-4 py-3.5 text-[15px] text-foreground"
className="rounded-[14px] border border-input-border bg-input px-4 py-3.5 text-base text-foreground"
/>
</View>

Expand Down
12 changes: 5 additions & 7 deletions apps/mobile/src/app/new/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -129,18 +129,18 @@ export default function NewTaskRoute() {
{items.length === 0 ? (
<View collapsable={false} className="items-center gap-3 rounded-[24px] bg-card px-6 py-8">
{projectEmptyState.loading ? <ActivityIndicator color={accentColor} /> : null}
<Text className="text-center text-[17px] font-t3-bold text-foreground">
<Text className="text-center text-lg font-t3-bold text-foreground">
{projectEmptyState.title}
</Text>
<Text className="text-center text-[14px] leading-[20px] text-foreground-muted">
<Text className="text-center text-sm leading-[20px] text-foreground-muted">
{projectEmptyState.detail}
</Text>
{!catalogState.hasReadyEnvironment ? (
<Pressable
className="mt-1 rounded-full bg-primary px-4 py-2.5 active:opacity-70"
onPress={() => router.push("/connections/new")}
>
<Text className="text-[13px] font-t3-bold text-primary-foreground">
<Text className="text-sm font-t3-bold text-primary-foreground">
Add environment
</Text>
</Pressable>
Expand All @@ -149,7 +149,7 @@ export default function NewTaskRoute() {
className="mt-1 rounded-full bg-primary px-4 py-2.5 active:opacity-70"
onPress={() => router.push("/new/add-project")}
>
<Text className="text-[13px] font-t3-bold text-primary-foreground">
<Text className="text-sm font-t3-bold text-primary-foreground">
Add new project
</Text>
</Pressable>
Expand Down Expand Up @@ -197,9 +197,7 @@ export default function NewTaskRoute() {
/>
</View>
<View className="flex-1">
<Text className="text-[16px] leading-[21px] font-t3-bold">
{item.title}
</Text>
<Text className="text-base leading-[21px] font-t3-bold">{item.title}</Text>
</View>
<SymbolView
name="chevron.right"
Expand Down
22 changes: 11 additions & 11 deletions apps/mobile/src/app/settings/environments.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ export default function SettingsEnvironmentsRouteScreen() {
type="monochrome"
/>
</View>
<Text className="text-center text-[14px] leading-[20px] text-foreground-muted">
<Text className="text-center text-sm leading-[20px] text-foreground-muted">
No environments connected yet.{"\n"}Tap{" "}
<Text className="font-t3-bold text-foreground">+</Text> to add one.
</Text>
Expand Down Expand Up @@ -160,7 +160,7 @@ function ConfiguredCloudEnvironmentRows(props: {
return (
<View collapsable={false} className="mt-5 gap-3">
<View className="flex-row items-center justify-between px-1">
<Text className="text-[13px] font-t3-bold uppercase text-foreground-muted">T3 Cloud</Text>
<Text className="text-sm font-t3-bold uppercase text-foreground-muted">T3 Cloud</Text>
<Pressable
accessibilityRole="button"
disabled={controller.relayDiscovery.isRefreshing}
Expand Down Expand Up @@ -204,16 +204,16 @@ function ConfiguredCloudEnvironmentRows(props: {
) : controller.relayDiscovery.isRefreshing ? (
<View collapsable={false} className="items-center gap-3 rounded-[24px] bg-card p-6">
<ActivityIndicator color={iconColor} />
<Text className="text-center text-[14px] leading-[20px] text-foreground-muted">
<Text className="text-center text-sm leading-[20px] text-foreground-muted">
Loading linked cloud environments.
</Text>
</View>
) : controller.relayDiscovery.error ? (
<View collapsable={false} className="gap-3 rounded-[24px] bg-card p-5">
<Text className="text-[15px] font-t3-bold text-foreground">
<Text className="text-base font-t3-bold text-foreground">
Could not load T3 Cloud environments
</Text>
<Text className="text-[13px] leading-[18px] text-foreground-muted">
<Text className="text-sm leading-[18px] text-foreground-muted">
{controller.relayDiscovery.error}
</Text>
{controller.relayDiscovery.errorTraceId ? (
Expand All @@ -222,7 +222,7 @@ function ConfiguredCloudEnvironmentRows(props: {
</View>
) : (
<View collapsable={false} className="rounded-[24px] bg-card p-5">
<Text className="text-[14px] leading-[20px] text-foreground-muted">
<Text className="text-sm leading-[20px] text-foreground-muted">
No additional linked cloud environments.
</Text>
</View>
Expand Down Expand Up @@ -361,7 +361,7 @@ function CloudEnvironmentRowShell(props: {
<View className="min-w-0 flex-row items-center gap-2">
<ConnectionStatusDot state={props.connectionState} pulse={shouldPulse} size={7} />
<Text
className="min-w-0 flex-shrink text-[16px] font-t3-bold leading-[21px] text-foreground"
className="min-w-0 flex-shrink text-base font-t3-bold leading-[21px] text-foreground"
numberOfLines={1}
>
{props.label}
Expand All @@ -370,7 +370,7 @@ function CloudEnvironmentRowShell(props: {
{props.connectionError ? (
<Text
aria-hidden
className={cn("absolute left-0 right-0 text-[12px] leading-[16px]", statusClassName)}
className={cn("absolute left-0 right-0 text-xs leading-[16px]", statusClassName)}
onTextLayout={onMeasuredErrorTextLayout}
style={{ opacity: 0, zIndex: -1 }}
>
Expand All @@ -384,7 +384,7 @@ function CloudEnvironmentRowShell(props: {
className="min-w-0 flex-row items-start gap-1"
>
<Text
className={cn("min-w-0 flex-1 text-[12px] leading-[16px]", statusClassName)}
className={cn("min-w-0 flex-1 text-xs leading-[16px]", statusClassName)}
numberOfLines={isErrorExpanded ? undefined : 1}
>
{statusText}
Expand All @@ -394,7 +394,7 @@ function CloudEnvironmentRowShell(props: {
<Text
accessibilityHint="Copies the trace ID"
accessibilityRole="button"
className={cn("text-[12px] leading-[16px] underline", statusClassName)}
className={cn("text-xs leading-[16px] underline", statusClassName)}
onLongPress={(event) => {
event.stopPropagation();
copyTextWithHaptic(errorTraceId);
Expand Down Expand Up @@ -446,7 +446,7 @@ function CopyTraceIdButton(props: { readonly traceId: string }) {
className="self-start flex-row items-center gap-1.5 rounded-full bg-subtle px-3 py-2 active:opacity-70"
>
<SymbolView name="doc.on.doc" size={12} tintColor={iconColor} type="monochrome" />
<Text className="text-[12px] font-t3-bold text-foreground">Copy trace ID</Text>
<Text className="text-xs font-t3-bold text-foreground">Copy trace ID</Text>
</Pressable>
);
}
14 changes: 7 additions & 7 deletions apps/mobile/src/app/settings/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,7 @@ function ConfiguredSettingsRouteScreen() {
onPress={openAccount}
/>
</SettingsSection>
<Text className="px-2 text-[13px] leading-[18px] text-foreground-muted">
<Text className="px-2 text-sm leading-[18px] text-foreground-muted">
T3 Code works locally without signing in. Cloud features are optional.
</Text>
</View>
Expand Down Expand Up @@ -389,7 +389,7 @@ type SymbolName = ComponentProps<typeof SymbolView>["name"];
function SettingsSection(props: { readonly title: string; readonly children: ReactNode }) {
return (
<View className="gap-2">
<Text className="px-2 text-[13px] font-t3-medium text-foreground-muted">{props.title}</Text>
<Text className="px-2 text-sm font-t3-medium text-foreground-muted">{props.title}</Text>
<View
className="overflow-hidden rounded-[28px] bg-card"
style={{ borderCurve: "continuous" }}
Expand All @@ -413,8 +413,8 @@ function AppSettingsSection() {
type="monochrome"
weight="regular"
/>
<Text className="flex-1 text-[17px] text-foreground">Version</Text>
<Text className="text-[17px] text-foreground-muted">Alpha</Text>
<Text className="flex-1 text-lg text-foreground">Version</Text>
<Text className="text-lg text-foreground-muted">Alpha</Text>
</View>
</SettingsSection>
);
Expand Down Expand Up @@ -444,13 +444,13 @@ function SettingsRow(props: {
style={{ opacity: props.disabled ? 0.45 : 1 }}
>
<SymbolView name={props.icon} size={22} tintColor={icon} type="monochrome" weight="regular" />
<Text className="shrink-0 text-[17px] text-foreground" numberOfLines={1}>
<Text className="shrink-0 text-lg text-foreground" numberOfLines={1}>
{props.label}
</Text>
<View className="min-w-0 flex-1 items-end">
{props.value ? (
<Text
className="max-w-[180px] text-right text-[16px] text-foreground-muted"
className="max-w-[180px] text-right text-base text-foreground-muted"
ellipsizeMode="middle"
numberOfLines={1}
>
Expand Down Expand Up @@ -502,7 +502,7 @@ function SettingsSwitchRow(props: {
style={{ opacity: props.disabled ? 0.45 : 1 }}
>
<SymbolView name={props.icon} size={22} tintColor={icon} type="monochrome" weight="regular" />
<Text className="flex-1 text-[17px] text-foreground">{props.label}</Text>
<Text className="flex-1 text-lg text-foreground">{props.label}</Text>
<Switch
disabled={props.disabled}
ios_backgroundColor={track}
Expand Down
2 changes: 1 addition & 1 deletion apps/mobile/src/components/AppText.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export function AppTextInput({
<RNTextInput
ref={ref}
className={cn(
"min-h-[54px] rounded-2xl border border-input-border bg-input px-3.5 py-3 font-sans text-[15px] text-foreground",
"min-h-[54px] rounded-2xl border border-input-border bg-input px-3.5 py-3 font-sans text-base text-foreground",
className,
)}
placeholderTextColor={placeholderTextColor ?? placeholderColor}
Expand Down
Loading
Loading