← All proposals

Code Diff

A Panel List of changed files.

Net-new componentOpen in Storybook

proposals/CodeDiff/HANDOFF.md82 lines · View on GitHub

Handoff: CodeDiff

What and why

An agent proposes or applies changes to files, and the person needs to review them in place, in a chat message or an approval report. PDS has the parts (Panel List, Code Block with language='diff', File Diff) but no pattern that puts them together. This is a Panel List of changed files: each row has the file icon and name, an optional File Diff (counts and bar), and an expand button that reveals the diff in a Code Block.

It is built from PDS parts, not copied, so the port is mostly the composition and a little CSS.

  • Figma / Jira: none. Source was Erika's reference image (Diff viewer.png): the list collapsed, the list expanded, and a single expanded file.
  • Context: context.md

Exploration and decisions

  • Composed from the package: PanelList, PanelRow, CodeBlock and FileDiff are all exported, so CodeDiff composes them. The only new CSS is the file name (code font) and the stats width.
  • The "diff variant" of Code Block is the existing language='diff'. No new Code Block variant.
  • File Diff is optional, shown when both additions and deletions are given. The reference has none; the approval report row had it.
  • Compact rows. The Panel List's paddingSize only sets block padding, and the rows are also held open by a 48px minimum height and 20px side padding in Panel Row that no prop changes. CodeDiff overrides those (--pds-spacing-2xl minimum height, --pds-spacing-s side padding) and defaults paddingSize to 2xs. Rows go from about 73px to 48px.

API

Prop Type Default Purpose
className string none Additional class names.
copyButtonLabel string none Aria-label and tooltip text for each diff's copy button.
files CodeDiffFile[] required The changed files, one expandable row each.
hasBorder PanelListProps['hasBorder'] true Outside border, passed to the Panel List.
hasCopyButton boolean false Show a copy button on each diff.
paddingSize PanelListProps['paddingSize'] '2xs' Block padding of each row. The Panel List's own default is m.

CodeDiffFile:

Field Type Purpose
additions number Added lines. Shows File Diff when set with deletions.
deletions number Removed lines.
diff string The diff text, in unified diff format.
expandButtonLabel string Aria-label for the row's expand button ("Show changes to composer.json"). Pass it translated.
id string Unique id.
name string File name shown in the row.

Variants and states: collapsed and expanded rows; with and without File Diff counts; with and without the copy button; with and without a border.

Tokens used

  • --pds-spacing-2xl
  • --pds-spacing-2xs
  • --pds-spacing-s
  • --pds-typography-ff-code
  • --pds-typography-size-s

Impact

From impact.md: no existing PDS component is reached. The additions are two rules scoped to .pds-code-diff that override .pds-panel-row and .pds-panel-row__main (the compact rows). They apply only inside a Code Diff. No other proposal depends on it.

Reused vs net-new

  • Reused: PanelList, PanelRow, CodeBlock, FileDiff (from the package), and the local Icon wrapper.
  • Net-new: .pds-code-diff with __file, __name and __stats. See custom.md (no custom variables, no raw values).

Accessibility

  • Each row's expand button takes expandButtonLabel, which names the file. Panel Row owns the expand and collapse semantics and keyboard behavior.
  • The copy button takes copyButtonLabel for its name and tooltip.
  • Diff colors come from the package's Code Block syntax tokens. Added and removed lines should not rely on color alone; check that the + and - markers show.
  • The a11y panel has not been run on these stories. Run it in light and dark before the port.

Decisions and open questions

  • Initially expanded rows. The reference shows rows already expanded, but the package Panel Row starts collapsed and has no prop for it. It needs an isDefaultExpanded on Panel Row, which is a change to the PDS component, not to this one.
  • File icon. fileDiff is a guess from the reference.
  • Row size. A size prop on Panel Row or Panel List would remove the CSS overrides.
  • Diff colors. Check that the added, removed and hunk-header colors match the reference.

Port notes

  • New composition. Where it lives is the engineer's call; the nearest home is next to Panel List in src/components/panels/. Use npm run generate:component, then copy the files over.
  • Swap the local Icon wrapper and mergeClasses for the real ones.

Preview

npm run storybook, then Proposals/Code Diff.