From ec9144fe98eedf0a9fcf32c196d6db562ced2afa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Hub=C3=ADk?= Date: Fri, 14 Aug 2026 16:50:19 +0200 Subject: [PATCH 1/2] fix(ui-appearance): apply Text Size and Content Width to the transcript on web Two Settings -> Appearance defects in the session transcript: - Text Size (uiFontScale) never applied to transcript markdown on web. Web Unistyles registers style values as non-enumerable, non-writable data properties; scaleTextStyle's clone kept those descriptors, the scaling assignment threw, and the fail-closed catch returned the original style. buildEnrichedMarkdownStyle then read the unscaled fontSize back off the raw object, pinning all markdown metrics at their 16px base regardless of the setting. scaleTextStyle now redefines numeric metrics on the clone (preserving enumerability so CSS-class-driven text rendering is untouched) and only fails closed for non-configurable metrics. - Content Width (uiContentWidthMode) only applied after a reload. Transcript row caps read the static layout.maxWidth getter inside Unistyles stylesheets, which evaluate once at registration. The transcript row owners (MessageView, ToolCallsGroupRow, ToolCallsGroupUnitRowFrame, PendingMessagesTranscriptBlock) now apply the reactive useLayoutMaxWidth() value, matching the already-reactive ChatListInternal/ChatHeaderView/ItemGroup consumers. Both proven RED->GREEN: scaleTextStyle and buildEnrichedMarkdownStyle against the exact web-Unistyles property shape, and a content-width component test verified failing on HEAD before the fix. --- .../enriched/useEnrichedMarkdownStyle.test.ts | 66 ++++++++++++++++ ...gesTranscriptBlock.discardFallback.test.ts | 1 + .../PendingMessagesTranscriptBlock.test.tsx | 1 + .../PendingMessagesTranscriptBlock.tsx | 8 +- .../sessions/transcript/MessageView.tsx | 6 +- .../toolCalls/ToolCallsGroupRow.tsx | 6 +- ...toolCallsGroupChrome.contentWidth.test.tsx | 76 +++++++++++++++++++ .../toolCalls/units/toolCallsGroupChrome.tsx | 6 +- .../components/ui/text/uiFontScale.test.ts | 29 +++++++ .../sources/components/ui/text/uiFontScale.ts | 26 ++++++- 10 files changed, 208 insertions(+), 17 deletions(-) create mode 100644 apps/ui/sources/components/markdown/enriched/useEnrichedMarkdownStyle.test.ts create mode 100644 apps/ui/sources/components/sessions/transcript/toolCalls/units/toolCallsGroupChrome.contentWidth.test.tsx diff --git a/apps/ui/sources/components/markdown/enriched/useEnrichedMarkdownStyle.test.ts b/apps/ui/sources/components/markdown/enriched/useEnrichedMarkdownStyle.test.ts new file mode 100644 index 0000000000..5b9ac73aa0 --- /dev/null +++ b/apps/ui/sources/components/markdown/enriched/useEnrichedMarkdownStyle.test.ts @@ -0,0 +1,66 @@ +import { describe, expect, it } from 'vitest'; + +import { buildEnrichedMarkdownStyle } from './useEnrichedMarkdownStyle'; + +const colors = { + text: { primary: '#111111', secondary: '#666666', link: '#0066cc' }, + surface: { inset: '#eeeeee', elevated: '#ffffff', selected: '#dddddd' }, + border: { default: '#cccccc' }, +} as const; + +// Mirrors the transcript's real web textStyle: a Unistyles-registered style whose numeric +// metrics are non-enumerable, non-writable (but configurable) data properties. +function createWebUnistylesTextStyle(values: Record): unknown { + const style: Record = {}; + Object.defineProperties( + style, + Object.fromEntries(Object.entries(values).map(([key, value]) => [key, { + value, + enumerable: false, + configurable: true, + }])), + ); + style.unistyles_test = {}; + return style; +} + +describe('buildEnrichedMarkdownStyle uiFontScale', () => { + it('scales the markdown metrics from a plain transcript textStyle', () => { + const bundle = buildEnrichedMarkdownStyle({ + colors, + profile: 'transcript', + uiFontScale: 1.3, + textStyle: { fontSize: 16, lineHeight: 24 }, + }); + + expect(bundle.markdownStyle.paragraph?.fontSize).toBe(20.8); + expect(bundle.markdownStyle.paragraph?.lineHeight).toBe(31.2); + expect(bundle.markdownStyle.codeBlock?.fontSize).toBe(18.2); + }); + + it('scales the markdown metrics from a web Unistyles transcript textStyle', () => { + const bundle = buildEnrichedMarkdownStyle({ + colors, + profile: 'transcript', + uiFontScale: 1.3, + textStyle: createWebUnistylesTextStyle({ fontSize: 16, lineHeight: 24 }) as never, + }); + + expect(bundle.markdownStyle.paragraph?.fontSize).toBe(20.8); + expect(bundle.markdownStyle.paragraph?.lineHeight).toBe(31.2); + expect(bundle.markdownStyle.list?.fontSize).toBe(20.8); + expect(bundle.markdownStyle.h1?.fontSize).toBe(31.2); + }); + + it('keeps the unscaled metrics at scale 1', () => { + const bundle = buildEnrichedMarkdownStyle({ + colors, + profile: 'transcript', + uiFontScale: 1, + textStyle: createWebUnistylesTextStyle({ fontSize: 16, lineHeight: 24 }) as never, + }); + + expect(bundle.markdownStyle.paragraph?.fontSize).toBe(16); + expect(bundle.markdownStyle.paragraph?.lineHeight).toBe(24); + }); +}); diff --git a/apps/ui/sources/components/sessions/pending/PendingMessagesTranscriptBlock.discardFallback.test.ts b/apps/ui/sources/components/sessions/pending/PendingMessagesTranscriptBlock.discardFallback.test.ts index 98b1745dea..91e385faf3 100644 --- a/apps/ui/sources/components/sessions/pending/PendingMessagesTranscriptBlock.discardFallback.test.ts +++ b/apps/ui/sources/components/sessions/pending/PendingMessagesTranscriptBlock.discardFallback.test.ts @@ -148,6 +148,7 @@ vi.mock('@/components/ui/scroll/useScrollEdgeFades', () => ({ vi.mock('@/components/ui/layout/layout', () => ({ layout: { maxWidth: 800, headerMaxWidth: 800 }, + useLayoutMaxWidth: () => 800, })); describe('PendingMessagesTranscriptBlock send cleanup failure', () => { diff --git a/apps/ui/sources/components/sessions/pending/PendingMessagesTranscriptBlock.test.tsx b/apps/ui/sources/components/sessions/pending/PendingMessagesTranscriptBlock.test.tsx index 4d78c21182..edf13b8a53 100644 --- a/apps/ui/sources/components/sessions/pending/PendingMessagesTranscriptBlock.test.tsx +++ b/apps/ui/sources/components/sessions/pending/PendingMessagesTranscriptBlock.test.tsx @@ -249,6 +249,7 @@ vi.mock('@/components/ui/scroll/useScrollEdgeFades', () => ({ vi.mock('@/components/ui/layout/layout', () => ({ layout: { maxWidth: 800, headerMaxWidth: 800 }, + useLayoutMaxWidth: () => 800, })); describe('PendingMessagesTranscriptBlock', () => { diff --git a/apps/ui/sources/components/sessions/pending/PendingMessagesTranscriptBlock.tsx b/apps/ui/sources/components/sessions/pending/PendingMessagesTranscriptBlock.tsx index 963cb1faa3..4128edf8c6 100644 --- a/apps/ui/sources/components/sessions/pending/PendingMessagesTranscriptBlock.tsx +++ b/apps/ui/sources/components/sessions/pending/PendingMessagesTranscriptBlock.tsx @@ -7,7 +7,7 @@ import { useSession, useSetting } from '@/sync/domains/state/storage'; import { sync } from '@/sync/sync'; import { Modal } from '@/modal'; import { MarkdownView } from '@/components/markdown/MarkdownView'; -import { layout } from '@/components/ui/layout/layout'; +import { useLayoutMaxWidth } from '@/components/ui/layout/layout'; import { Text } from '@/components/ui/text/Text'; import { ActivitySpinner } from '@/components/ui/feedback/ActivitySpinner'; import { t } from '@/text'; @@ -202,6 +202,7 @@ export function PendingMessagesTranscriptBlock(props: Readonly<{ onEditPendingMessage?: (request: PendingMessageEditRequest) => void | Promise; }>) { const { theme } = useUnistyles(); + const contentMaxWidth = useLayoutMaxWidth(); const session = useSession(props.sessionId); const pendingInputServerId = session?.serverId ?? resolvePreferredServerIdForSessionId(props.sessionId); const serverFeaturesSnapshot = useServerFeaturesSnapshotForServerId(pendingInputServerId ?? null, { @@ -1383,9 +1384,9 @@ export function PendingMessagesTranscriptBlock(props: Readonly<{ return ( - + - + ({ flexDirection: 'column', flexGrow: 1, flexBasis: 0, - maxWidth: layout.maxWidth, }, userMessageContainer: { maxWidth: '100%', diff --git a/apps/ui/sources/components/sessions/transcript/MessageView.tsx b/apps/ui/sources/components/sessions/transcript/MessageView.tsx index e9051add7b..6ad3b2700e 100644 --- a/apps/ui/sources/components/sessions/transcript/MessageView.tsx +++ b/apps/ui/sources/components/sessions/transcript/MessageView.tsx @@ -7,7 +7,7 @@ import { t } from '@/text'; import { Message, UserTextMessage, AgentTextMessage, ToolCallMessage } from "@/sync/domains/messages/messageTypes"; import { Metadata } from "@/sync/domains/state/storageTypes"; import type { OpenApprovalArtifactForSession } from '@/sync/domains/artifacts/approvalArtifacts'; -import { layout } from "@/components/ui/layout/layout"; +import { useLayoutMaxWidth } from "@/components/ui/layout/layout"; import { ToolView } from '@/components/tools/shell/views/ToolView'; import { ToolTimelineRow } from '@/components/tools/shell/views/ToolTimelineRow'; import { resolveToolStatusIndicatorKind } from '@/components/tools/shell/presentation/resolveToolStatusIndicatorKind'; @@ -313,6 +313,7 @@ export const MessageViewWithSessionCommon = React.memo(function MessageViewWithS toolChromeCommon: TranscriptToolChromeCommon; toolRouteCommon: TranscriptToolRouteCommon; }) { + const contentMaxWidth = useLayoutMaxWidth(); const interaction = props.interaction ?? FAIL_CLOSED_TRANSCRIPT_INTERACTION; const canFork = interaction.canFork === true; const committedCanForkRef = React.useRef(canFork); @@ -333,7 +334,7 @@ export const MessageViewWithSessionCommon = React.memo(function MessageViewWithS ) === 'hidden') return null; return ( - + ({ flexDirection: 'column', flexGrow: 1, flexBasis: 0, - maxWidth: layout.maxWidth, }, recoveredHistoryIndicator: { marginHorizontal: 16, diff --git a/apps/ui/sources/components/sessions/transcript/toolCalls/ToolCallsGroupRow.tsx b/apps/ui/sources/components/sessions/transcript/toolCalls/ToolCallsGroupRow.tsx index 1c4ccd7838..0cc406bdbd 100644 --- a/apps/ui/sources/components/sessions/transcript/toolCalls/ToolCallsGroupRow.tsx +++ b/apps/ui/sources/components/sessions/transcript/toolCalls/ToolCallsGroupRow.tsx @@ -13,7 +13,7 @@ import { ToolCallsGroupViewWithSessionCommon, } from '@/components/sessions/transcript/turns/toolCalls/ToolCallsGroupView'; import { TRANSCRIPT_WEB_TOOL_GROUP_PREPEND_ANCHOR_TEST_ID_PREFIX } from '@/components/sessions/transcript/viewport/prepend/webTranscriptPrependAnchor'; -import { layout } from '@/components/ui/layout/layout'; +import { useLayoutMaxWidth } from '@/components/ui/layout/layout'; import type { TranscriptInteraction } from '@/utils/sessions/deriveTranscriptInteraction'; import { resolveInactiveSessionToolCallFailure } from '@/components/tools/shell/permissions/resolveInactiveSessionToolCallFailure'; import { resolveToolStatusIndicatorKind } from '@/components/tools/shell/presentation/resolveToolStatusIndicatorKind'; @@ -54,6 +54,7 @@ export const ToolCallsGroupRow = React.memo(function ToolCallsGroupRow(props: To export const ToolCallsGroupRowWithSessionCommon = React.memo(function ToolCallsGroupRowWithSessionCommon( props: ToolCallsGroupRowProps & TranscriptSessionCommonProps, ) { + const contentMaxWidth = useLayoutMaxWidth(); const toolMessagesRaw = useMessagesByIds(props.sessionId, props.toolMessageIds); const toolMessages = React.useMemo(() => { const byId = new Map(); @@ -113,7 +114,7 @@ export const ToolCallsGroupRowWithSessionCommon = React.memo(function ToolCallsG - + ({ centeredContent: { flexGrow: 1, flexBasis: 0, - maxWidth: layout.maxWidth, }, })); diff --git a/apps/ui/sources/components/sessions/transcript/toolCalls/units/toolCallsGroupChrome.contentWidth.test.tsx b/apps/ui/sources/components/sessions/transcript/toolCalls/units/toolCallsGroupChrome.contentWidth.test.tsx new file mode 100644 index 0000000000..c0ee8f5ad4 --- /dev/null +++ b/apps/ui/sources/components/sessions/transcript/toolCalls/units/toolCallsGroupChrome.contentWidth.test.tsx @@ -0,0 +1,76 @@ +import React from 'react'; +import { act } from 'react-test-renderer'; +import { describe, expect, it, vi } from 'vitest'; + +import { renderScreen } from '@/dev/testkit'; +import { installToolCallsGroupViewCommonModuleMocks } from '@/components/sessions/transcript/turns/toolCalls/toolCallsGroupViewTestHelpers'; +import { flattenStyleProp } from './toolCallsGroupUnitsTestFixtures'; + +(globalThis as any).IS_REACT_ACT_ENVIRONMENT = true; + +const shared = vi.hoisted(() => ({ + contentWidthMode: 'compact' as 'compact' | 'medium' | 'full', +})); + +installToolCallsGroupViewCommonModuleMocks({ + reactNative: async () => { + const { createReactNativeWebMock } = await import('@/dev/testkit/mocks/reactNative'); + return createReactNativeWebMock({ + Platform: { OS: 'web', select: (values: any) => values?.web ?? values?.default ?? null }, + }); + }, + storage: async (importOriginal) => { + const { createStorageModuleMock } = await import('@/dev/testkit/mocks/storage'); + return createStorageModuleMock({ + importOriginal, + overrides: { + useLocalSetting: ((key: string) => { + if (key === 'uiContentWidthMode') return shared.contentWidthMode; + if (key === 'uiFontScale') return 1; + return undefined; + }) as typeof import('@/sync/domains/state/storage')['useLocalSetting'], + }, + }); + }, +}); + +vi.mock('@/sync/domains/state/storageStore', () => ({ + getStorage: () => ({ + getState: () => ({ + localSettings: { + uiContentWidthMode: shared.contentWidthMode, + }, + }), + }), +})); + +function findRowFrameMaxWidth(screen: Awaited>): unknown { + const matchingNode = screen.findAllByType('View' as never).find((node: any) => { + const style = flattenStyleProp(node.props.style); + return style.flexGrow === 1 && style.flexBasis === 0 && style.maxWidth !== undefined; + }); + return matchingNode ? flattenStyleProp((matchingNode as any).props.style).maxWidth : undefined; +} + +describe('ToolCallsGroupUnitRowFrame content width', () => { + it('updates the row width cap when the local content width setting changes', async () => { + shared.contentWidthMode = 'compact'; + const { ToolCallsGroupUnitRowFrame } = await import('./toolCallsGroupChrome'); + + const renderElement = () => ( + + {null} + + ); + const screen = await renderScreen(renderElement()); + + expect(findRowFrameMaxWidth(screen)).toBe(850); + + shared.contentWidthMode = 'full'; + await act(async () => { + screen.tree.update(renderElement()); + }); + + expect(findRowFrameMaxWidth(screen)).toBe(Number.POSITIVE_INFINITY); + }); +}); diff --git a/apps/ui/sources/components/sessions/transcript/toolCalls/units/toolCallsGroupChrome.tsx b/apps/ui/sources/components/sessions/transcript/toolCalls/units/toolCallsGroupChrome.tsx index 5e6b91b471..64368f2214 100644 --- a/apps/ui/sources/components/sessions/transcript/toolCalls/units/toolCallsGroupChrome.tsx +++ b/apps/ui/sources/components/sessions/transcript/toolCalls/units/toolCallsGroupChrome.tsx @@ -10,7 +10,7 @@ import { ActivitySpinner, iconMatchedSpinnerSize } from '@/components/ui/feedbac import { Text } from '@/components/ui/text/Text'; import { t } from '@/text'; import { Typography } from '@/constants/Typography'; -import { layout } from '@/components/ui/layout/layout'; +import { useLayoutMaxWidth } from '@/components/ui/layout/layout'; import { resolveInactiveSessionToolCallFailure } from '@/components/tools/shell/permissions/resolveInactiveSessionToolCallFailure'; import { resolveToolStatusIndicatorKind } from '@/components/tools/shell/presentation/resolveToolStatusIndicatorKind'; @@ -98,9 +98,10 @@ export function ToolCallsGroupUnitRowFrame(props: Readonly<{ unitTestID: string; children: React.ReactNode; }>) { + const contentMaxWidth = useLayoutMaxWidth(); return ( - + ({ centeredContent: { flexGrow: 1, flexBasis: 0, - maxWidth: layout.maxWidth, }, container: { marginHorizontal: 16, diff --git a/apps/ui/sources/components/ui/text/uiFontScale.test.ts b/apps/ui/sources/components/ui/text/uiFontScale.test.ts index 9e7c737005..704457bc65 100644 --- a/apps/ui/sources/components/ui/text/uiFontScale.test.ts +++ b/apps/ui/sources/components/ui/text/uiFontScale.test.ts @@ -88,6 +88,35 @@ describe('uiFontScale', () => { expect(scaled[marker]).toEqual({ className: 'unistyles_x' }); }); + it('scales web Unistyles styles whose metrics are non-enumerable, non-writable properties', () => { + // Mirrors react-native-unistyles/src/web removeInlineStyles + assignSecrets: style values + // become non-enumerable, non-writable (but configurable) data properties, and the secret + // lives under an enumerable `unistyles_*` key without the native `uni__getStyles` shape. + const style: any = {}; + Object.defineProperties(style, { + fontSize: { value: 16, enumerable: false, configurable: true }, + lineHeight: { value: 24, enumerable: false, configurable: true }, + }); + style.unistyles_web1 = {}; + Object.defineProperty(style.unistyles_web1, '__uni__key', { + value: 'transcriptMarkdownText', + enumerable: false, + configurable: true, + }); + + const scaled = scaleTextStyle(style, 1.3) as any; + + expect(scaled).not.toBe(style); + expect(scaled.fontSize).toBe(20.8); + expect(scaled.lineHeight).toBe(31.2); + // Enumerability is preserved so the web renderer keeps sizing text via CSS classes. + expect(Object.getOwnPropertyDescriptor(scaled, 'fontSize')?.enumerable).toBe(false); + expect(scaled.unistyles_web1).toBe(style.unistyles_web1); + // The original registered style must never be mutated. + expect(style.fontSize).toBe(16); + expect(style.lineHeight).toBe(24); + }); + it('does not crash on nullish styles', () => { expect(scaleTextStyle(null, 1.1)).toBe(null); expect(scaleTextStyle(undefined, 1.1)).toBe(undefined); diff --git a/apps/ui/sources/components/ui/text/uiFontScale.ts b/apps/ui/sources/components/ui/text/uiFontScale.ts index 9238eb7721..a6702d908e 100644 --- a/apps/ui/sources/components/ui/text/uiFontScale.ts +++ b/apps/ui/sources/components/ui/text/uiFontScale.ts @@ -16,6 +16,23 @@ function clonePreservingOwnProps(entry: T): T { } } +function setScaledMetric(target: any, key: string, value: number): void { + const descriptor = Object.getOwnPropertyDescriptor(target, key); + if (!descriptor || (descriptor.writable === true && !descriptor.get && !descriptor.set)) { + target[key] = value; + return; + } + // Web Unistyles registers style values as non-enumerable, non-writable data properties + // (see react-native-unistyles/src/web removeInlineStyles). Redefine the metric on the + // clone while preserving its enumerability so CSS-class-driven rendering is unaffected. + Object.defineProperty(target, key, { + value, + enumerable: descriptor.enumerable, + configurable: true, + writable: true, + }); +} + function scaleNumericTextMetrics(entry: any, uiFontScale: number): any { const hasFontSize = typeof entry?.fontSize === 'number'; const hasLineHeight = typeof entry?.lineHeight === 'number'; @@ -24,12 +41,13 @@ function scaleNumericTextMetrics(entry: any, uiFontScale: number): any { const next: any = clonePreservingOwnProps(entry as any); try { - if (hasFontSize) next.fontSize = roundTo2(next.fontSize * uiFontScale); - if (hasLineHeight) next.lineHeight = roundTo2(next.lineHeight * uiFontScale); - if (hasLetterSpacing) next.letterSpacing = roundTo2(next.letterSpacing * uiFontScale); + if (hasFontSize) setScaledMetric(next, 'fontSize', roundTo2(entry.fontSize * uiFontScale)); + if (hasLineHeight) setScaledMetric(next, 'lineHeight', roundTo2(entry.lineHeight * uiFontScale)); + if (hasLetterSpacing) setScaledMetric(next, 'letterSpacing', roundTo2(entry.letterSpacing * uiFontScale)); return next; } catch { - // If the style object is non-writable (or uses accessors), avoid corrupting opaque metadata. + // A non-configurable, non-writable metric cannot be scaled without corrupting opaque + // metadata; fail closed to the unscaled style. return entry; } } From b342bad6172778d2ba773230ff3353c4d7b114e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Hub=C3=ADk?= Date: Fri, 14 Aug 2026 17:22:09 +0200 Subject: [PATCH 2/2] test(ui-appearance): tighten types in transcript appearance tests Address review: type the web-Unistyles fixture as TextStyle plus a unistyles-keyed record instead of casting call sites, use React's act export, the typed act-environment global, a generic Platform.select shape, and ReactTestInstance for rendered nodes. --- .../enriched/useEnrichedMarkdownStyle.test.ts | 12 +++++++----- .../toolCallsGroupChrome.contentWidth.test.tsx | 15 +++++++++------ 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/apps/ui/sources/components/markdown/enriched/useEnrichedMarkdownStyle.test.ts b/apps/ui/sources/components/markdown/enriched/useEnrichedMarkdownStyle.test.ts index 5b9ac73aa0..f4964d749f 100644 --- a/apps/ui/sources/components/markdown/enriched/useEnrichedMarkdownStyle.test.ts +++ b/apps/ui/sources/components/markdown/enriched/useEnrichedMarkdownStyle.test.ts @@ -1,3 +1,4 @@ +import type { TextStyle } from 'react-native'; import { describe, expect, it } from 'vitest'; import { buildEnrichedMarkdownStyle } from './useEnrichedMarkdownStyle'; @@ -8,10 +9,12 @@ const colors = { border: { default: '#cccccc' }, } as const; +type WebUnistylesTextStyle = TextStyle & Record<`unistyles_${string}`, unknown>; + // Mirrors the transcript's real web textStyle: a Unistyles-registered style whose numeric // metrics are non-enumerable, non-writable (but configurable) data properties. -function createWebUnistylesTextStyle(values: Record): unknown { - const style: Record = {}; +function createWebUnistylesTextStyle(values: Readonly>): WebUnistylesTextStyle { + const style: WebUnistylesTextStyle = { unistyles_test: {} }; Object.defineProperties( style, Object.fromEntries(Object.entries(values).map(([key, value]) => [key, { @@ -20,7 +23,6 @@ function createWebUnistylesTextStyle(values: Record): unknown { configurable: true, }])), ); - style.unistyles_test = {}; return style; } @@ -43,7 +45,7 @@ describe('buildEnrichedMarkdownStyle uiFontScale', () => { colors, profile: 'transcript', uiFontScale: 1.3, - textStyle: createWebUnistylesTextStyle({ fontSize: 16, lineHeight: 24 }) as never, + textStyle: createWebUnistylesTextStyle({ fontSize: 16, lineHeight: 24 }), }); expect(bundle.markdownStyle.paragraph?.fontSize).toBe(20.8); @@ -57,7 +59,7 @@ describe('buildEnrichedMarkdownStyle uiFontScale', () => { colors, profile: 'transcript', uiFontScale: 1, - textStyle: createWebUnistylesTextStyle({ fontSize: 16, lineHeight: 24 }) as never, + textStyle: createWebUnistylesTextStyle({ fontSize: 16, lineHeight: 24 }), }); expect(bundle.markdownStyle.paragraph?.fontSize).toBe(16); diff --git a/apps/ui/sources/components/sessions/transcript/toolCalls/units/toolCallsGroupChrome.contentWidth.test.tsx b/apps/ui/sources/components/sessions/transcript/toolCalls/units/toolCallsGroupChrome.contentWidth.test.tsx index c0ee8f5ad4..1112e82732 100644 --- a/apps/ui/sources/components/sessions/transcript/toolCalls/units/toolCallsGroupChrome.contentWidth.test.tsx +++ b/apps/ui/sources/components/sessions/transcript/toolCalls/units/toolCallsGroupChrome.contentWidth.test.tsx @@ -1,12 +1,12 @@ -import React from 'react'; -import { act } from 'react-test-renderer'; +import React, { act } from 'react'; +import type { ReactTestInstance } from 'react-test-renderer'; import { describe, expect, it, vi } from 'vitest'; import { renderScreen } from '@/dev/testkit'; import { installToolCallsGroupViewCommonModuleMocks } from '@/components/sessions/transcript/turns/toolCalls/toolCallsGroupViewTestHelpers'; import { flattenStyleProp } from './toolCallsGroupUnitsTestFixtures'; -(globalThis as any).IS_REACT_ACT_ENVIRONMENT = true; +(globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true; const shared = vi.hoisted(() => ({ contentWidthMode: 'compact' as 'compact' | 'medium' | 'full', @@ -16,7 +16,10 @@ installToolCallsGroupViewCommonModuleMocks({ reactNative: async () => { const { createReactNativeWebMock } = await import('@/dev/testkit/mocks/reactNative'); return createReactNativeWebMock({ - Platform: { OS: 'web', select: (values: any) => values?.web ?? values?.default ?? null }, + Platform: { + OS: 'web', + select: (values: Readonly<{ web?: T; default?: T }>) => values.web ?? values.default ?? null, + }, }); }, storage: async (importOriginal) => { @@ -45,11 +48,11 @@ vi.mock('@/sync/domains/state/storageStore', () => ({ })); function findRowFrameMaxWidth(screen: Awaited>): unknown { - const matchingNode = screen.findAllByType('View' as never).find((node: any) => { + const matchingNode = screen.findAllByType('View' as never).find((node: ReactTestInstance) => { const style = flattenStyleProp(node.props.style); return style.flexGrow === 1 && style.flexBasis === 0 && style.maxWidth !== undefined; }); - return matchingNode ? flattenStyleProp((matchingNode as any).props.style).maxWidth : undefined; + return matchingNode ? flattenStyleProp(matchingNode.props.style).maxWidth : undefined; } describe('ToolCallsGroupUnitRowFrame content width', () => {