mirror of
https://github.com/backnotprop/plannotator.git
synced 2026-09-14 14:17:26 +08:00
cbc6186a15
* 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).
63 lines
1.7 KiB
TypeScript
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>
|
|
)}
|
|
</>
|
|
);
|
|
};
|