Files
Robert Dailey cbc6186a15 fix(ui): align list markers to first line in clean diff view (#838)
* fix(ui): align list marker to first line in clean diff view

* refactor(ui): extract list-item marker and body into ListItemBody

Three render paths (BlockRenderer and two in PlanCleanDiffView)
duplicated the same marker-plus-paragraph scaffold. A recent alignment
fix had to be applied to each surface independently, which exposed the
duplication. The shared structure now lives in ListItemBody; call sites
keep their own row wrapper with surface-specific concerns (indent, data
attributes, hover props, interactivity).
2026-06-02 11:18:52 -07:00

63 lines
1.7 KiB
TypeScript

import React from 'react';
import { ListMarker } from './ListMarker';
/**
* Shared list-item body: the marker plus the item's text content. Used by the
* main Viewer (BlockRenderer) and the plan-diff clean view (both the inline
* modified-block render and SimpleBlockRenderer).
*
* Callers own the surrounding row element so each surface keeps its own
* concerns (indent, data attributes, hover-prop spread, diff wrapper classes).
* This component owns the parts that must stay identical: marker selection and
* the single-paragraph `<span>` vs multi-paragraph `<div><p>...</p></div>`
* split, so a fix to either never has to be repeated per surface.
*/
interface ListItemBodyProps {
level: number;
ordered?: boolean;
orderedIndex?: number | null;
checked?: boolean; // undefined = not a checkbox
interactive?: boolean;
onToggle?: () => void;
textClassName: string;
content: string;
renderInline: (text: string) => React.ReactNode;
}
export const ListItemBody: React.FC<ListItemBodyProps> = ({
level,
ordered,
orderedIndex,
checked,
interactive,
onToggle,
textClassName,
content,
renderInline,
}) => {
const paragraphs = content.split(/\n\n+/);
return (
<>
<ListMarker
level={level}
ordered={ordered}
orderedIndex={orderedIndex}
checked={checked}
interactive={interactive}
onToggle={onToggle}
/>
{paragraphs.length === 1 ? (
<span className={textClassName}>{renderInline(content)}</span>
) : (
<div className={textClassName}>
{paragraphs.map((para, i) => (
<p key={i} className={i > 0 ? 'mt-3' : ''}>
{renderInline(para)}
</p>
))}
</div>
)}
</>
);
};