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,CodeBlockandFileDiffare all exported, soCodeDiffcomposes 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
additionsanddeletionsare given. The reference has none; the approval report row had it. - Compact rows. The Panel List's
paddingSizeonly 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.CodeDiffoverrides those (--pds-spacing-2xlminimum height,--pds-spacing-sside padding) and defaultspaddingSizeto2xs. 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 localIconwrapper. - Net-new:
.pds-code-diffwith__file,__nameand__stats. Seecustom.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
copyButtonLabelfor 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
isDefaultExpandedon Panel Row, which is a change to the PDS component, not to this one. - File icon.
fileDiffis 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/. Usenpm run generate:component, then copy the files over. - Swap the local
Iconwrapper andmergeClassesfor the real ones.
Preview
npm run storybook, then Proposals/Code Diff.