Skip to content

refactor(prompt-field): use swc-action-button for action buttons - #6615

Draft
rubencarvalho wants to merge 4 commits into
mainfrom
ruben/refactor-prompt-field-action-buttons
Draft

refactor(prompt-field): use swc-action-button for action buttons#6615
rubencarvalho wants to merge 4 commits into
mainfrom
ruben/refactor-prompt-field-action-buttons

Conversation

@rubencarvalho

@rubencarvalho rubencarvalho commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Description

Replaces the five bespoke native <button> elements in the Prompt field pattern (send, stop, upload, and the two artifact scroll chevrons) with <swc-action-button>, reproducing their existing looks through the component's public custom properties. Net −65 lines.

  • Send / stop — round via --swc-action-button-border-radius: corner-radius-full plus background/content-color/down-state-transform overrides.
  • Upload — quiet icon-only action button.
  • Scroll prev/next — converted while preserving the fade mask. The ::before opaque panel stays on the host at z-index: -1, behind the shadow-DOM button face, so the old ::after repaint is no longer needed (the face is a descendant that paints above the negative-z mask).
  • Accessible names move from aria-label to accessible-label (the component forwards it to the inner <button>'s aria-label).
  • Scroll chevrons use <swc-ui-icon icon="chevron">; send, stop, and upload keep their existing SVG icons.
  • Focus handling: the artifact-strip keyboard handler matched a focused chevron by strict identity (active === button), which breaks once the chevron is an swc-action-button with delegatesFocus — focus lands on its inner shadow <button>, not the host. It now uses deepContains(button, active), the util already used elsewhere in the file for the same cross-shadow check. The tests use the same idiom.

Motivation and context

The Prompt field's action affordances were hand-rolled native buttons with ~180 lines of bespoke CSS, duplicating states (hover/focus/disabled/press) that swc-action-button already provides. Consolidating onto the shared component removes that surface and keeps the pattern consistent with the rest of the 2nd-gen set.

Related issue(s)

  • fixes [Issue Number]

Screenshots (if appropriate)

Send/stop circle geometry and the scroll-chevron mask compositing should be confirmed via Chromatic; expect a VRT re-baseline.

Author's checklist

  • I have read the CONTRIBUTING and PULL_REQUESTS documents.
  • I have reviewed at the Accessibility Practices for this feature, see: Aria Practices
  • I have added automated tests to cover my changes.
  • I have included a well-written changeset if my change needs to be published.
  • I have included updated documentation if my change required it.

Reviewer's checklist

  • Includes a Github Issue with appropriate flag or Jira ticket number without a link
  • Includes thoughtfully written changeset if changes suggested include patch, minor, or major features
  • Automated tests cover all use cases and follow best practices for writing
  • Validated on all supported browsers
  • All VRTs are approved before the author can update Golden Hash

Manual review test cases

  • Send and stop render as filled round buttons

    1. Open the Prompt field pattern in Storybook
    2. Type text, then observe the send button; set generating to see the stop button
    3. Expect both to be filled circles with correct hover/press/disabled treatment
  • Artifact scroll chevrons page and mask correctly

    1. Open a Prompt field story with enough artifacts to overflow the strip
    2. Use the prev/next chevrons to page
    3. Expect the fade mask to cap the tiles cleanly at each edge, with the chevron circle painted over it

Device review

  • Did it pass in Desktop?
  • Did it pass in (emulated) Mobile?
  • Did it pass in (emulated) iPad?

Accessibility testing checklist

  • Keyboard (required — document steps below)

    1. Open a Prompt field story with overflowing artifacts
    2. Tab into the strip; from a tile Tab reaches its Close button, then the Next (>) chevron
    3. Shift + Tab from the Next chevron returns focus into the currently visible tiles (not wherever focus was before paging)
    4. Activate a chevron with Enter/Space; expect the strip to page and focus to remain on the chevron control
    5. When a chevron becomes non-actionable at a strip end, expect focus to stay on it (it uses aria-disabled, not the disabled property) with no focus jump
    6. Confirm the send/stop button activates with Enter and Space
  • Screen reader (required — document steps below)

    1. With VoiceOver/NVDA, focus each control
    2. Expect the send, stop, upload, and scroll buttons to announce role "button" with their accessible names ("Send", "Stop generating", "Add attachment", "Show previous/more attachments")
    3. Confirm the chevrons announce their disabled state via aria-disabled at the strip ends

Replace the five bespoke native <button> elements (send, stop, upload, and
the two artifact scroll chevrons) with <swc-action-button>, reproducing their
looks through the component's custom properties: corner-radius-full for the
round send/stop, corner-radius-800 for the scroll chevrons, plus background,
content-color, and down-state-transform overrides.

The scroll chevrons keep their fade mask: the ::before opaque panel stays on
the host at z-index -1, behind the shadow-DOM button face, so no ::after
repaint is needed. Accessible names move from aria-label to accessible-label
(forwarded to the inner button). Scroll chevrons use swc-ui-icon; send, stop,
and upload keep their existing SVG icons.

The keyboard-nav handler now matches a focused chevron via a delegatesFocus
-aware check (host or its shadow descendant) instead of strict identity, and
the tests assert focus and accessible name accordingly.
@changeset-bot

changeset-bot Bot commented Aug 13, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 583a879

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@rubencarvalho
rubencarvalho marked this pull request as draft August 13, 2026 10:12
@github-actions

Copy link
Copy Markdown
Contributor

📚 Branch Preview Links

🔍 Gen1 Visual Regression Test Results

When a visual regression test fails (or has previously failed while working on this branch), its results can be found in the following URLs:

Deployed to Azure Blob Storage: pr-6615

If the changes are expected, update the current_golden_images_cache hash in the circleci config to accept the new images. Instructions are included in that file.
If the changes are unexpected, you can investigate the cause of the differences and update the code accordingly.

…m comment

Replace the hand-rolled isChevron helper (getRootNode().host) with the
existing deepContains() util already used elsewhere in this file for the same
cross-shadow focus check. Drop the redundant scroll-chevron header comment;
the ::before rule's own comment already explains the z-index/paint order.
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