From 3be257ba1d646f9d2cbae6e0ff93b5bf3f2f6095 Mon Sep 17 00:00:00 2001
From: imccyu <276526105+imccyu@users.noreply.github.com>
Date: Tue, 4 Aug 2026 16:04:26 +0800
Subject: [PATCH] fix(web): preserve polish accessibility contracts
---
.../snapshots/sidebar-scrollbar/geometry.expected.md | 4 ++--
.../client/ui-conversation/src/client/chat/StatsLine.tsx | 2 +-
.../src/client/skeleton/PermissionSelect.tsx | 4 +++-
.../ui-conversation/tests/chat-stats-bash-sample.spec.tsx | 8 ++++----
packages/client/ui-conversation/tests/input-bar.spec.tsx | 2 ++
.../client/ui-sidebar/src/client/SidebarRoot.module.css | 4 ++--
6 files changed, 14 insertions(+), 10 deletions(-)
diff --git a/apps/web/tests/snapshots/sidebar-scrollbar/geometry.expected.md b/apps/web/tests/snapshots/sidebar-scrollbar/geometry.expected.md
index 4349532ef8..0bbb0328d6 100644
--- a/apps/web/tests/snapshots/sidebar-scrollbar/geometry.expected.md
+++ b/apps/web/tests/snapshots/sidebar-scrollbar/geometry.expected.md
@@ -24,8 +24,8 @@
- scrollbar-width: auto
- scrollbar-color: auto
- ::-webkit-scrollbar-thumb:hover declarations: var(--dsh-scrollbar-thumb-hover)
-- --dsh-scrollbar-thumb: rgb(60, 60, 61)
-- --dsh-scrollbar-thumb-hover: rgb(84, 85, 87)
+- --dsh-scrollbar-thumb: rgb(84, 85, 87)
+- --dsh-scrollbar-thumb-hover: rgb(101, 103, 107)
- list overflows: true
- reserved band: 8px
- relative time covered by the bar: 0px
diff --git a/packages/client/ui-conversation/src/client/chat/StatsLine.tsx b/packages/client/ui-conversation/src/client/chat/StatsLine.tsx
index 4cb5df2565..ceffffb59a 100644
--- a/packages/client/ui-conversation/src/client/chat/StatsLine.tsx
+++ b/packages/client/ui-conversation/src/client/chat/StatsLine.tsx
@@ -152,7 +152,7 @@ export const StatsLine = memo(function StatsLine({ useSession, useProjection }:
{groups.map((group, i) => (
- {i > 0 && |}
+ {i > 0 && <>|{' '}>}
{group}
))}
diff --git a/packages/client/ui-conversation/src/client/skeleton/PermissionSelect.tsx b/packages/client/ui-conversation/src/client/skeleton/PermissionSelect.tsx
index 632c8c020b..73f4080c1c 100644
--- a/packages/client/ui-conversation/src/client/skeleton/PermissionSelect.tsx
+++ b/packages/client/ui-conversation/src/client/skeleton/PermissionSelect.tsx
@@ -148,7 +148,9 @@ export function PermissionSelect({ value, locked, command, t }: PermissionSelect
)}
{current === undefined ? displayName(currentValue) : optionLabel(current)}
{/* Same glyph + open rotation as the sibling ModelSelect trigger. */}
-
+
+
+
}
/>
diff --git a/packages/client/ui-conversation/tests/chat-stats-bash-sample.spec.tsx b/packages/client/ui-conversation/tests/chat-stats-bash-sample.spec.tsx
index 95da35f267..c8eae5d8bd 100644
--- a/packages/client/ui-conversation/tests/chat-stats-bash-sample.spec.tsx
+++ b/packages/client/ui-conversation/tests/chat-stats-bash-sample.spec.tsx
@@ -133,7 +133,7 @@ describe('StatsLine', () => {
const view = render()
// No timing on the fixture: the duration group drops out whole. Tokens come
// from the projection, so paging the window cannot change them.
- expect(view.container.textContent).toBe('1 turns · 1 steps|Cache hit 90%|Input 100 tok · Output 5 tok')
+ expect(view.container.textContent).toBe('1 turns · 1 steps| Cache hit 90%| Input 100 tok · Output 5 tok')
const empty = makeSource()
const emptyView = render( {
contextPressure: { pressureTokens: 32_000, contextWindow: 128_000 },
})} />)
expect(view.container.textContent)
- .toBe('Context 25% of 128K|Cache hit 90%|Input 100 tok · Output 5 tok')
+ .toBe('Context 25% of 128K| Cache hit 90%| Input 100 tok · Output 5 tok')
})
it('renders context occupancy only when the projection knows a capacity', () => {
@@ -196,7 +196,7 @@ describe('StatsLine', () => {
const view = render()
- expect(view.container.textContent).toBe('1 turns · 1 steps|Input 0 tok · Output 7 tok')
+ expect(view.container.textContent).toBe('1 turns · 1 steps| Input 0 tok · Output 7 tok')
})
it('includes cache writes in billed input and the cache-hit denominator', () => {
@@ -210,7 +210,7 @@ describe('StatsLine', () => {
},
})} />)
expect(view.container.textContent)
- .toBe('1 turns · 1 steps|Cache hit 45%|Input 200 tok · Output 7 tok')
+ .toBe('1 turns · 1 steps| Cache hit 45%| Input 200 tok · Output 7 tok')
})
it('renders ZERO times during streaming chunk frames (RFC hard acceptance)', () => {
diff --git a/packages/client/ui-conversation/tests/input-bar.spec.tsx b/packages/client/ui-conversation/tests/input-bar.spec.tsx
index 002704ce4c..7de9f2be74 100644
--- a/packages/client/ui-conversation/tests/input-bar.spec.tsx
+++ b/packages/client/ui-conversation/tests/input-bar.spec.tsx
@@ -595,6 +595,8 @@ describe('command launcher chrome and control seats', () => {
const trigger = view.getByLabelText(/^访问模式/) as HTMLButtonElement
// Title-case display is presentation only; the menu ids stay machine names.
expect(trigger.textContent).toBe('Read Only')
+ expect([...trigger.querySelectorAll('svg')]
+ .every(icon => icon.closest('[aria-hidden="true"]') !== null)).toBe(true)
fireEvent.click(trigger)
const items = view.getAllByRole('menuitem')
expect(items.map(o => o.textContent)).toEqual(['Read Only', 'Workspace Write', 'Full access'])
diff --git a/packages/client/ui-sidebar/src/client/SidebarRoot.module.css b/packages/client/ui-sidebar/src/client/SidebarRoot.module.css
index 3013570d16..cdb5641d89 100644
--- a/packages/client/ui-sidebar/src/client/SidebarRoot.module.css
+++ b/packages/client/ui-sidebar/src/client/SidebarRoot.module.css
@@ -23,8 +23,8 @@
}
.root:hover {
- --dsh-scrollbar-thumb: var(--dsw-alias-scrollbar-bg-l1);
- --dsh-scrollbar-thumb-hover: var(--dsw-alias-scrollbar-hover-l1);
+ --dsh-scrollbar-thumb: var(--dsw-alias-scrollbar-bg-l2);
+ --dsh-scrollbar-thumb-hover: var(--dsw-alias-scrollbar-hover-l2);
}
/* Rail geometry (figma rail spec): 36x36 control boxes centered in the 56px