Skip to content

fix(chat): a11y + UX polish caught by live browser smoke (0.0.25)#198

Merged
blove merged 4 commits into
mainfrom
claude/a11y-and-ux-polish-0.0.25
May 5, 2026
Merged

fix(chat): a11y + UX polish caught by live browser smoke (0.0.25)#198
blove merged 4 commits into
mainfrom
claude/a11y-and-ux-polish-0.0.25

Conversation

@blove
Copy link
Copy Markdown
Contributor

@blove blove commented May 5, 2026

Summary

Continued live browser smoke testing in `~/tmp/ngaf` — exercising primitives I hadn't touched yet (model picker, action buttons, multi-line input) — caught 3 more bugs. All fold into this 0.0.25 release.

Fixes

  1. Textarea auto-resize. `rows="1"` with no auto-grow logic — multi-line input via Shift+Enter was hidden behind the fixed 24px height. Live DOM showed `scrollHeight: 72px` vs `clientHeight: 24px`. Added an `effect()` that resizes `el.style.height` to `scrollHeight` on every `messageText` change, capped at 200px (~8 lines) before switching to overflow scrolling.

  2. Escape closes model picker from trigger. `ChatSelectComponent` handled Escape only when keydown fired inside the menu. Click-to-open leaves focus on the trigger, so Escape was ignored — menu stayed open until click-outside. Added Escape branch to `onTriggerKeydown`.

  3. `aria-pressed` on rating toggle buttons. Thumbs-up/down visually flipped via `is-active` class but no `aria-pressed` attribute. Screen readers couldn't communicate toggle state. Added `[attr.aria-pressed]` bound to the `rating` signal.

Synchronized version bump

All 16 `@ngaf/*` libraries → `0.0.25`.

Backstory

Five sub-PRs of cumulative live-browser-smoke discovery this session:

PR Version Bugs fixed
#196 0.0.23 Missing exports + a2ui ESM .js extensions
#197 0.0.24 Table row dispatch + 4 citation/task rendering bugs
#198 0.0.25 This — 3 a11y + UX polish

Test plan

  • `npx nx run chat:test` green (regression tests added for textarea auto-resize and trigger-Escape)
  • `npx nx run chat:lint` green
  • Live Chrome re-validation against 0.0.25 once published

Three fixes from continued live Chrome smoke testing of @ngaf/chat 0.0.24:

1. **Textarea auto-resize**: rows="1" with no auto-grow logic meant
   multi-line input via Shift+Enter was hidden behind the fixed 24px
   height (scrollHeight grew to 72px+ while clientHeight stayed at 24px).
   Added an effect() that resizes el.style.height to scrollHeight on
   every messageText change, capped at 200px (~8 lines) before
   switching to overflow scrolling.

2. **Escape closes model picker from trigger**: ChatSelectComponent
   handled Escape only on keydown inside the menu (focused option).
   When user clicked the trigger to open and pressed Escape without
   arrowing into the menu, the keypress hit the trigger which only
   handled Enter/Space/ArrowDown — Escape was ignored and the menu
   stayed open until click-outside. Added Escape branch to
   onTriggerKeydown.

3. **aria-pressed on rating toggle buttons**: thumbs-up/down rendered
   visual is-active class but no aria-pressed attribute. Screen
   readers couldn't communicate toggle state. Added [attr.aria-pressed]
   bound to the rating signal.

Synchronized version bump to 0.0.25 across all 16 @Ngaf libs.
@vercel
Copy link
Copy Markdown

vercel Bot commented May 5, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
cacheplane Ready Ready Preview, Comment May 5, 2026 7:01pm

Request Review

…anel

Live Chrome smoke against published 0.0.24 caught: chat-citations is
template-conditioned on @if (message()?.role === 'assistant' && message()),
but the chat composition did not pass [message]="message" to
<chat-message>. So message() was always undefined inside chat-message,
the @if branch was falsy, and <chat-citations> never rendered — even when
markdown citation defs existed in the message content.

This was the missing piece of the 0.0.24 sources panel fix. Three of the
four fixes worked end-to-end (table rows, citation no-url span, task-list
checkbox layout); the panel itself silently never appeared.

Fix: add [message]="message" to the assistant <chat-message> in
chat.component.ts. The user/system variants don't need it.
Live Chrome smoke caught: when navigator.clipboard.writeText rejects
(permissions, non-secure context, document-not-focused), the catch
silently swallowed the error. The textarea+execCommand legacy path was
only used when clipboard API was missing — not when it failed.

Refactored: try Async Clipboard API first; on rejection, fall through
to the textarea legacy path. Only set copied state when at least one
path succeeded.
Live Chrome smoke caught:

1. Wide tables (8+ columns or long content) had no overflow handling.
   chat-md-table used 'display: contents' so the inner <table> dictated
   width, with parent at viewport width — wider tables overflowed
   horizontally with no scroll wrapper. Fixed: chat-md-table now uses
   'display: block; overflow-x: auto; max-width: 100%' so wide tables
   scroll within their message bubble. Row/cell elements stay
   layout-transparent so browser table layout still works.

2. Broken images (404 / invalid URL) showed only the browser's default
   broken-image icon with no readable alt text. Fixed: <img> now binds
   (error) to a 'failed' signal that swaps to a styled fallback pill
   showing the alt text and a placeholder icon. Pill uses the same
   surface-alt background as code blocks for consistency.
@blove blove merged commit a72bb0e into main May 5, 2026
14 checks passed
@blove blove deleted the claude/a11y-and-ux-polish-0.0.25 branch May 5, 2026 21:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant