7 file(s), +312 / -16 lines
| Path | Role | + | - |
|---|---|---|---|
| src/components/matter-detail/brief/editable-field-with-history.stories.tsx | Component | +110 | -0 |
| src/components/matter-detail/brief/frame-summary-history.test.tsx | Component | +50 | -0 |
| src/components/matter-detail/brief/frame-summary-history.tsx | Component | +30 | -13 |
| src/components/shared/editable-surface-preset.ts | Component | +10 | -0 |
| src/components/shared/editable-surface.tsx | Component | +6 | -3 |
| src/components/shared/snapshot-preview.test.tsx | Component | +41 | -0 |
| src/components/shared/snapshot-preview.tsx | Component | +65 | -0 |
Story-2035 made light/full reachable on the
EditableSurface primitive. But the surrounding
gutter rail — the History popover/modal, the Save control,
⌘Z/⌘⇧Z undo/redo, and the Mira icon, all living in
EditableFieldWithHistory — still assumed plain strings: it
dropped a raw version.value into the timeline previews and only
ever mounted a plain edit surface. This story lifts the rail so it operates
on markdown snapshots, preset-agnostic. One rail now wraps
plain, light, or full — so the Brief
and the Draft Workspace share it. The Brief stays on plain and
is byte-for-byte unchanged.
EditableFieldWithHistory takes a preset
(plain | light | full, default plain) and threads
it into the live EditableSurface. That alone gives a
light/full field a working History + Save +
undo/redo rail with a formatting surface — AC 1.
SnapshotPreview
(src/components/shared/snapshot-preview.tsx) — a read-only
render of a markdown snapshot through the same engine + preset
strategy as the live surface (RFD §4). Every timeline spot that used to
print {version.value} as raw text — the recent-history
popover, the full-history modal, and the "viewing a past version" body —
now renders through it. So **bold** in a light
snapshot shows as bold in the history list, never as literal asterisks.
value is the markdown snapshot string, appended
append-only exactly as today's plain strings are (pramaan-docs ADR-153).
"Restore this version" appends the chosen snapshot verbatim as a
new version — the round-trip identity is the preset serializer's
(proved in editable-surface-preset.test.ts), and the rail
just carries the string through — AC 2.
plain strategy still parses a snapshot as a JSON doc, not
markdown, so a <, a leading #, or **
render as literal characters in previews too. The Brief's summary /
Core-dispute rail behaves identically — AC 3.
BLOCK_FORMAT_CLASS in editable-surface-preset.ts,
shared by the live surface and SnapshotPreview so an edited
value and its history snapshot render identically.
| File | Change |
|---|---|
src/components/shared/snapshot-preview.tsx | new — read-only markdown snapshot render |
src/components/shared/editable-surface-preset.ts | export shared BLOCK_FORMAT_CLASS |
src/components/shared/editable-surface.tsx | use BLOCK_FORMAT_CLASS (no behaviour change) |
src/components/matter-detail/brief/frame-summary-history.tsx | preset prop; previews → SnapshotPreview |
src/components/matter-detail/brief/editable-field-with-history.stories.tsx | light/full markdown-rail stories |
src/components/shared/snapshot-preview.test.tsx | new — plain-literal vs markdown-formatted render |
src/components/matter-detail/brief/frame-summary-history.test.tsx | new — restore round-trips a markdown snapshot verbatim |
pnpm lint — clean (one pre-existing no-img-element warning, unrelated).pnpm test — full suite green, incl. the two new files.pnpm build — green.MatterDetail/EditableFieldWithHistory →
LightPreset, LightHistoryMenu, FullPreset,
FullViewingPast, FullHistoryModal demonstrate the rail on
markdown; the existing plain CoreDispute/FrameSummaryHistory
stories prove no regression.
No backend wiring — versions are still mock/prop-fed (the live
append-only frame-version read is a separate story). The Brief is not moved
off plain; that is the frame-contract decision in RFD §3a. No
new i18n copy: the rail's prototype copy is unchanged and untouched.