Treść z repozytorium z zachowaniem nagłówków, przykładów, kodu, tabel, linków i obrazów.
Pierre Integration Guard
Plannotator's code review UI wraps @pierre/diffs — an open-source diff renderer that uses Shadow DOM. The integration is concentrated in a single file but relies on undocumented internals (shadow DOM selectors, CSS variable names, grid layout assumptions). This skill helps verify changes don't break that contract.
Source of Truth
- Upstream repo: https://github.com/pierrecomputer/pierre/tree/main/packages/diffs
- Local types:
node_modules/@pierre/diffs/dist/(.d.tsfiles) - Integration point:
packages/review-editor/components/DiffViewer.tsx - Current version: check
packages/review-editor/package.jsonfor the pinned version
Always verify against the upstream repo or local .d.ts files — don't rely on memory of the API shape.
What We Import
import { FileDiff } from '@pierre/diffs/react';
import { getSingularPatch, processFile } from '@pierre/diffs';These are the only three imports. DiffViewer.tsx is the only file that touches Pierre.
API Surface to Guard
1. Component Props (FileDiff)
Read the current prop types from node_modules/@pierre/diffs/dist/react/index.d.ts or the upstream source. The props we use:
| Prop | Type | Notes | |
|---|---|---|---|
fileDiff | FileDiffMetadata | From getSingularPatch() or processFile() | |
options | FileDiffOptions<T> | See options table below | |
lineAnnotations | DiffLineAnnotation<T>[] | { side, lineNumber, metadata } | |
selectedLines | `SelectedLineRange \ | null` | { start, end, side } |
renderAnnotation | (ann) => ReactNode | Custom inline annotation renderer | |
renderHoverUtility | (getHoveredLine) => ReactNode | The + button on hover (deprecated upstream — watch for removal) |
2. Options Object
| Option | Value We Pass | Risk | |
|---|---|---|---|
themeType | `'dark' \ | 'light'` | Low — standard enum |
unsafeCSS | CSS string | High — targets internal selectors | |
diffStyle | `'split' \ | 'unified'` | Low — standard enum |
diffIndicators | 'bars' | Low | |
hunkSeparators | 'line-info' | Low | |
enableLineSelection | true | Low | |
enableHoverUtility | true | Medium — deprecated prop | |
onLineSelectionEnd | callback | Medium — signature could change |
3. Shadow DOM Selectors (via unsafeCSS)
These are the selectors we inject CSS rules against. They target data-* attributes inside Pierre's shadow DOM. If Pierre renames or removes any of these, our styling breaks silently.
Currently used:
:host— shadow root[data-diff]— root diff container[data-file]— file wrapper[data-diffs-header]— header bar[data-error-wrapper]— error display[data-virtualizer-buffer]— virtual scroll buffer[data-file-info]— file metadata row[data-column-number]— line number gutter[data-diffs-header] [data-title]— title (we hide it)[data-diff-type='split']— split layout mode[data-overflow='scroll']/[data-overflow='wrap']— overflow mode
4. CSS Variables We Override
We override these --diffs-* variables to theme Pierre:
--diffs-bg,--diffs-fg— base colors--diffs-dark-bg,--diffs-light-bg— theme-specific backgrounds--diffs-dark,--diffs-light— theme-specific foregrounds
5. CSS Variables We Inject (Custom)
We set these on a wrapper div outside the shadow DOM, relying on CSS custom property inheritance:
--split-left,--split-right— control the split pane grid ratio
The unsafeCSS grid override references these: grid-template-columns: var(--split-left, 1fr) var(--split-right, 1fr). The 1fr fallback ensures the layout is safe if the variables aren't set.
6. Grid Layout Assumption
Pierre's split view uses CSS Grid with grid-template-columns: 1fr 1fr. We override this for the resizable split pane. If Pierre changes its layout engine (e.g., to flexbox or a different grid structure), the override will stop working.
How to verify: In the upstream source, search for grid-template-columns in the diff component styles.
Verification Checklist
When reviewing changes that touch the Pierre integration, check:
Props & Types
- [ ] Read the current
.d.tsfiles to confirm prop names and types haven't changed - [ ] Check if
renderHoverUtilityis still supported (it's deprecated — may be removed) - [ ] Verify
DiffLineAnnotationstill usesside: 'deletions' | 'additions'(not'old' | 'new') - [ ] Confirm
SelectedLineRangeshape:{ start, end, side? }
Shadow DOM Selectors
- [ ] Grep the upstream source for each
data-*attribute we target inunsafeCSS - [ ] If upgrading the package version, diff the old and new CSS/HTML output for renamed attributes
- [ ] Test both
splitandunifiedviews — selectors are layout-dependent
CSS Variables
- [ ] Grep upstream for
--diffs-bg,--diffs-fg, and other variables we override - [ ] Verify the variable names haven't been renamed or removed
- [ ] Check that
!importantis still needed (Pierre may change specificity)
Theme Compliance
- [ ] New UI elements must use theme tokens (
bg-border,bg-primary, etc.), not hardcoded colors likebg-blue-500 - [ ] The existing
ResizeHandlecomponent inpackages/ui/components/ResizeHandle.tsxsets the visual convention — match it
Build & Runtime
- [ ] Run
bun run dev:reviewand verify the diff renders in both split and unified modes - [ ] Check the browser console for Pierre warnings (e.g.,
parseLineType: Invalid firstChar) - [ ] Test with add-only and delete-only files (Pierre doesn't render split grid for these)
- [ ] If changing UI code, remember build order:
bun run --cwd apps/review build && bun run build:hook
When Upgrading @pierre/diffs
- Check the upstream changelog / commit history at https://github.com/pierrecomputer/pierre
- Diff the
.d.tsfiles between old and new versions:
# Before upgrading, snapshot current types
cp -r node_modules/@pierre/diffs/dist /tmp/pierre-old
# After upgrading
diff -r /tmp/pierre-old node_modules/@pierre/diffs/dist- Search for renamed/removed data attributes in the new version
- Run through the full verification checklist above
- Test the resizable split pane — it depends on grid layout internals

